<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>白纸上涂鸦の博客</title>
  
  <subtitle>记录生活的点点滴滴</subtitle>
  <link href="https://shaogithub.github.io/atom.xml" rel="self"/>
  
  <link href="https://shaogithub.github.io/"/>
  <updated>2023-12-09T06:48:51.096Z</updated>
  <id>https://shaogithub.github.io/</id>
  
  <author>
    <name>Mr.shao</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>如何购买ChatGPT Plus会员</title>
    <link href="https://shaogithub.github.io/2023/12/09/%E5%A6%82%E4%BD%95%E8%B4%AD%E4%B9%B0ChatGPT-Plus%E4%BC%9A%E5%91%98/"/>
    <id>https://shaogithub.github.io/2023/12/09/%E5%A6%82%E4%BD%95%E8%B4%AD%E4%B9%B0ChatGPT-Plus%E4%BC%9A%E5%91%98/</id>
    <published>2023-12-09T05:40:30.000Z</published>
    <updated>2023-12-09T06:48:51.096Z</updated>
    
    <content type="html"><![CDATA[<h2 id="重要提醒"><a href="#重要提醒" class="headerlink" title="重要提醒"></a>重要提醒</h2><blockquote><p>由于大家使用的网络和设备条件各不相同，无法保证按照该教程操作一定能成功😂 最近问的人比较多，所以做个统一整理，仅供参考~</p></blockquote><ul><li>可能面临的财产损失（包括但不限于），请务必知悉：<ul><li>注册美区账号后，成功充值了礼品卡，但无法使用礼品卡购买ChatGPT Plus，且，已充值的服务卡不支持退费（损失礼品卡费用）。</li><li>充值成功，但账号被ChatGPT官方检测为异常，导致账号被封禁（丢失账号+损失充值费）。</li></ul></li><li>教程来自网络搜集，<code>部分操作可能随软件功能更新而失效</code>，所以，想充值的请尽快~</li><li>成功充值ChatGPT Plus后，就能同时在ChatGPT APP和ChatGPT网页端，使用GPT-4啦！</li><li>每月费用：20美金</li><li>一个观点：是否充值主要看个人需求，如果觉得3.5给出的答复已经令人满意，那就继续使用。如果感觉每月20刀也不算啥不愿负担的成本，那么不妨开上一月试试。</li></ul><span id="more"></span><h2 id="以下是购买ChatGPT-Plus会员的两种方案"><a href="#以下是购买ChatGPT-Plus会员的两种方案" class="headerlink" title="以下是购买ChatGPT Plus会员的两种方案"></a>以下是购买ChatGPT Plus会员的两种方案</h2><h3 id="方案1：iOS渠道使用支付宝购买"><a href="#方案1：iOS渠道使用支付宝购买" class="headerlink" title="方案1：iOS渠道使用支付宝购买"></a>方案1：iOS渠道使用支付宝购买</h3><ol><li>工具清单：</li></ol><ul><li>支付宝账号</li><li>一个给力的可以访问ChatGTP的电脑（出国自行查询）</li><li>一个ChatGTP账号</li><li>一台<code>IPhone or IPad</code>：因为需要使用移动端APP Store，Mac似乎不行。</li><li>一个<code>美区 App Store 账号</code>：注册教程可参考：<a href="https://youtu.be/Y51VMx4NOfk"></a></li></ul><ol start="2"><li>操作步骤：<br>当你拥有以上所有工具后，可参考以下操作步骤：</li></ol><ul><li>在你的IPhone&#x2F;IPad上退出中国区账号，登录美区账号。</li><li>登录美区账号后，在App Store搜索ChatGPT，完成下载安装。</li><li>通过支付宝，充值美区App Store礼品卡（共20美金），具体步骤可参考：<a href="https://youtu.be/W3chc223K-w"></a></li><li>打开ChatGPT软件，登录账号后，付费升级ChatGPT Plus，操作步骤可参考：<a href="https://youtu.be/2iEeUVhb96U"></a></li><li>完成升级后，你可以直接在PC网页端登录ChatGPT账号，勾选CPT-4进行使用~</li></ul><ol start="3"><li>注意事项：</li></ol><ul><li>1个美区AppStore账号只能绑定一个ChatGPT账号（有6个月锁定期）</li><li>充值完成后，APP页面显示有延迟，即：明明付钱了，软件也提示你完成订阅了，但subscription 仍显示为 Free，用不了GPT-4，此时，可退出软件重进 or 撂下手机等待一段时间，软件会在稍后更新订阅情况。<h3 id="方案2：Wildcard虚拟卡充值"><a href="#方案2：Wildcard虚拟卡充值" class="headerlink" title="方案2：Wildcard虚拟卡充值"></a>方案2：Wildcard虚拟卡充值</h3></li></ul><ol><li>工具清单：</li></ol><ul><li>Wildcard虚拟卡，注册链接：<a href="https://bewildcard.com/"></a></li></ul><ol start="2"><li>操作步骤：<br>Wildcard官网有很详细的图文和视频教程，这里不再赘述。<br>参考教程：<br><a href="https://help.bewildcard.com/zh-CN/articles/8073056-chatgpt-plus-%E8%AE%A2%E9%98%85%E6%95%99%E7%A8%8B">ChatGPT Plus 订阅教程 | WildCard 帮助中心</a><br><a href="https://www.bilibili.com/video/BV1XB4y1Z7JX/?vd_source=1bad45916757fb4466675bb959020f08">WildCard 开通 ChatGPT Plus 详细教程_哔哩哔哩_bilibili</a><br><a href="https://help.bewildcard.com/zh-CN/articles/8479911-chatgpt-plus-%E5%A6%82%E4%BD%95%E5%8F%AA%E8%AE%A2%E9%98%851%E4%B8%AA%E6%9C%88">ChatGPT Plus 如何只订阅1个月 | WildCard 帮助中心</a></li></ol><h4 id="常见问题1：订阅需要排队怎么办？"><a href="#常见问题1：订阅需要排队怎么办？" class="headerlink" title="常见问题1：订阅需要排队怎么办？"></a>常见问题1：订阅需要排队怎么办？</h4><p>点击upgrade后，如果出现以下界面提示需要排队开通，则可以采用下面的步骤跳过排队。<br><img src="/./2023/12/09/%E5%A6%82%E4%BD%95%E8%B4%AD%E4%B9%B0ChatGPT-Plus%E4%BC%9A%E5%91%98/upgrade.png"></p><ol><li>关闭这个界面；</li><li>按下F12，打开控制台（console），输入如下代码：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">fetch(&quot;/api/auth/session&quot;).then(r =&gt; r.json()).then((&#123; accessToken &#125;) =&gt; &#123;</span><br><span class="line">fetch(&quot;/backend-api/payments/checkout&quot;, &#123;</span><br><span class="line">&quot;method&quot;: &quot;POST&quot;,</span><br><span class="line">&quot;headers&quot;: &#123;&quot;authorization&quot;: `Bearer $&#123;accessToken&#125;`,&#125;,</span><br><span class="line">&#125;).then(r =&gt; r.json()).then(d =&gt; window.open(d.url))</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><img src="/./2023/12/09/%E5%A6%82%E4%BD%95%E8%B4%AD%E4%B9%B0ChatGPT-Plus%E4%BC%9A%E5%91%98/upgradeerror.png"></li><li>自动跳转到付款界面：<br><img src="/./2023/12/09/%E5%A6%82%E4%BD%95%E8%B4%AD%E4%B9%B0ChatGPT-Plus%E4%BC%9A%E5%91%98/fukuanjiemian.png"><h4 id="常见问题2：付款不成功怎么办？比如弹出“我们未能验证您的支付方式。请选择另一支付方式并重试”"><a href="#常见问题2：付款不成功怎么办？比如弹出“我们未能验证您的支付方式。请选择另一支付方式并重试”" class="headerlink" title="常见问题2：付款不成功怎么办？比如弹出“我们未能验证您的支付方式。请选择另一支付方式并重试”"></a>常见问题2：付款不成功怎么办？比如弹出“我们未能验证您的支付方式。请选择另一支付方式并重试”</h4>最简单有效的办法是找网站客服帮忙订阅，我就是本地环境与登录远程环境都重试多次均不成功，找客服让他们的海外同事开通了<br>需要准备：</li></ol><ul><li>你的OpenAI账号和密码</li><li>你的wildcard卡片和账单地址的全部信息（点击「复制全部」按钮即可）<br><img src="/./2023/12/09/%E5%A6%82%E4%BD%95%E8%B4%AD%E4%B9%B0ChatGPT-Plus%E4%BC%9A%E5%91%98/allcopy.png"></li><li><a href="http://pay.openai.com/"></a>开头的那个全部网址，点击 Upgrade 跳转后的那个ChatGPT的付款页面</li><li><img src="/./2023/12/09/%E5%A6%82%E4%BD%95%E8%B4%AD%E4%B9%B0ChatGPT-Plus%E4%BC%9A%E5%91%98/upgradecopyall.png"></li></ul><blockquote><p>点击右下角对话图标即可唤起客服，把 OpenAI 的账户密码提供给客服，让他们的海外同事帮您进行绑定，成功率接近100%。</p></blockquote><h4 id="注意事项："><a href="#注意事项：" class="headerlink" title="注意事项："></a>注意事项：</h4><p>1张虚拟卡最多可以给4个ChatGPT 账号开通Plus，如果超出数量，可以点击“多卡”，申请一张新卡</p><h4 id="安卓手机如何下载安装ChatGPT？"><a href="#安卓手机如何下载安装ChatGPT？" class="headerlink" title="安卓手机如何下载安装ChatGPT？"></a>安卓手机如何下载安装ChatGPT？</h4><p>安卓手机需要先安装谷歌三件套，安装完成后即可进入Play商店搜索ChatGPT下载。<br>安装谷歌三件套视频教程：<a href="https://www.youtube.com/watch?v=RcT1wlvs7R8"></a><br>Google Play 下载链接：<a href="https://drive.google.com/drive/folders/1U5FIAHrCGEl2zN4_giiNHNjpnvNyIiuF"></a></p>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;重要提醒&quot;&gt;&lt;a href=&quot;#重要提醒&quot; class=&quot;headerlink&quot; title=&quot;重要提醒&quot;&gt;&lt;/a&gt;重要提醒&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;由于大家使用的网络和设备条件各不相同，无法保证按照该教程操作一定能成功😂 最近问的人比较多，所以做个统一整理，仅供参考~&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;可能面临的财产损失（包括但不限于），请务必知悉：&lt;ul&gt;
&lt;li&gt;注册美区账号后，成功充值了礼品卡，但无法使用礼品卡购买ChatGPT Plus，且，已充值的服务卡不支持退费（损失礼品卡费用）。&lt;/li&gt;
&lt;li&gt;充值成功，但账号被ChatGPT官方检测为异常，导致账号被封禁（丢失账号+损失充值费）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;教程来自网络搜集，&lt;code&gt;部分操作可能随软件功能更新而失效&lt;/code&gt;，所以，想充值的请尽快~&lt;/li&gt;
&lt;li&gt;成功充值ChatGPT Plus后，就能同时在ChatGPT APP和ChatGPT网页端，使用GPT-4啦！&lt;/li&gt;
&lt;li&gt;每月费用：20美金&lt;/li&gt;
&lt;li&gt;一个观点：是否充值主要看个人需求，如果觉得3.5给出的答复已经令人满意，那就继续使用。如果感觉每月20刀也不算啥不愿负担的成本，那么不妨开上一月试试。&lt;/li&gt;
&lt;/ul&gt;</summary>
    
    
    
    
  </entry>
  
  <entry>
    <title>16字节内存对齐算法探究</title>
    <link href="https://shaogithub.github.io/2022/05/01/16%E5%AD%97%E8%8A%82%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E7%AE%97%E6%B3%95%E6%8E%A2%E7%A9%B6/"/>
    <id>https://shaogithub.github.io/2022/05/01/16%E5%AD%97%E8%8A%82%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E7%AE%97%E6%B3%95%E6%8E%A2%E7%A9%B6/</id>
    <published>2022-05-01T03:30:53.000Z</published>
    <updated>2022-05-01T03:47:08.158Z</updated>
    
    <content type="html"><![CDATA[<p>16字节内存对齐算法我们先从下方的两个两种方法来探究：</p><ul><li>alloc源码分析中的align16：</li><li>malloc源码分析中的segregated_size_to_fit</li></ul><span id="more"></span><h3 id="align16：-16字节对齐算法"><a href="#align16：-16字节对齐算法" class="headerlink" title="align16： 16字节对齐算法"></a>align16： 16字节对齐算法</h3><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">inline</span> size_t align16(size_t x) &#123;</span><br><span class="line">    <span class="keyword">return</span> (x + size_t(<span class="number">15</span>)) &amp; ~size_t(<span class="number">15</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/./2022/05/01/16%E5%AD%97%E8%8A%82%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E7%AE%97%E6%B3%95%E6%8E%A2%E7%A9%B6/image_1.png" alt="image.png"></p><ul><li>首先将原始的内存 8 与 size_t(15)相加，得到 8 + 15 &#x3D; 23</li><li>将 size_t(15) 即 15进行~（取反）操作，~（取反）的规则是：1变为0，0变为1</li><li>最后将 23 与 15的取反结果 进行 &amp;（与）操作，&amp;（与）的规则是：都是1为1，反之为0，最后的结果为 16，即内存的大小是以16的倍数增加的</li></ul><h3 id="segregated-size-to-fit：-16字节对齐算法"><a href="#segregated-size-to-fit：-16字节对齐算法" class="headerlink" title="segregated_size_to_fit： 16字节对齐算法"></a>segregated_size_to_fit： 16字节对齐算法</h3><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> SHIFT_NANO_QUANTUM4</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> NANO_REGIME_QUANTA_SIZE(1 &lt;&lt; SHIFT_NANO_QUANTUM)<span class="comment">// 16</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">static</span> MALLOC_INLINE size_t</span><br><span class="line">segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)</span><br><span class="line">&#123;</span><br><span class="line">size_t k, slot_bytes;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (<span class="number">0</span> == size) &#123;</span><br><span class="line">size = NANO_REGIME_QUANTA_SIZE; <span class="comment">// Historical behavior</span></span><br><span class="line">&#125;</span><br><span class="line">k = (size + NANO_REGIME_QUANTA_SIZE - <span class="number">1</span>) &gt;&gt; SHIFT_NANO_QUANTUM; <span class="comment">// round up and shift for number of quanta</span></span><br><span class="line">slot_bytes = k &lt;&lt; SHIFT_NANO_QUANTUM;<span class="comment">// multiply by power of two quanta size</span></span><br><span class="line">*pKey = k - <span class="number">1</span>;<span class="comment">// Zero-based!</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> slot_bytes;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>算法原理：<br>k + 15 &gt;&gt; 4 &lt;&lt; 4 ，其中 右移4 + 左移4 相当于将后4位抹零，跟 k&#x2F;16 * 16一样 ，是16字节对齐算法，小于16就成0了<br>以 k &#x3D; 2为例，如下图所示<br><img src="/./2022/05/01/16%E5%AD%97%E8%8A%82%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E7%AE%97%E6%B3%95%E6%8E%A2%E7%A9%B6/image_2.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;16字节内存对齐算法我们先从下方的两个两种方法来探究：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;alloc源码分析中的align16：&lt;/li&gt;
&lt;li&gt;malloc源码分析中的segregated_size_to_fit&lt;/li&gt;
&lt;/ul&gt;</summary>
    
    
    
    <category term="iOS底层原理" scheme="https://shaogithub.github.io/categories/iOS%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    
    
    <category term="iOS" scheme="https://shaogithub.github.io/tags/iOS/"/>
    
    <category term="iOS底层原理" scheme="https://shaogithub.github.io/tags/iOS%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>iOS-底层原理03：内存对齐原理探究</title>
    <link href="https://shaogithub.github.io/2022/04/20/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8603%EF%BC%9A%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/"/>
    <id>https://shaogithub.github.io/2022/04/20/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8603%EF%BC%9A%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/</id>
    <published>2022-04-20T14:30:13.000Z</published>
    <updated>2022-04-24T15:08:54.674Z</updated>
    
    <content type="html"><![CDATA[<h3 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h3><p>在开始探究内存对齐原理之前，我们先来两个问题：</p><ol><li>内存对齐原则是什么？</li></ol><ul><li>数据成员对齐规则：结构体（struct）或联合体（union）的数据成员，第一个数据成员放在 offset 为 0 的地方，以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小（只要该成员有子成员，比如说数组、结构体等）的整数倍开始（比如int为4字节，则要从4的整数倍地址开始存储）</li><li>结构体作为成员：如果一个结构里有某些结构体成员，则结构体成员要从其内部最大元素大小的整数倍地址开始存储（strcut a里存有 struct b，b里有结构体char，int 等，那么b应该从8的整数倍开始存储）</li><li>结构体的总大小，也就是sizeof的结果，必须是其内部最大成员的整数倍，不足的需要补齐<span id="more"></span></li></ul><ol start="2"><li>获取内存大小的方法有哪些？</li></ol><ul><li>sizeof</li><li>class_getInstanceSize</li><li>malloc_size</li></ul><p>下面我们通过程序运行来看一下三种获取内存大小的方法有什么不同：</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#import <span class="string">&lt;Foundation/Foundation.h&gt;</span></span></span><br><span class="line"><span class="meta">#import <span class="string">&lt;objc/runtime.h&gt;</span></span></span><br><span class="line"><span class="meta">#import <span class="string">&lt;malloc/malloc.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> main(<span class="type">int</span> argc, <span class="keyword">const</span> <span class="type">char</span> * argv[]) &#123;</span><br><span class="line">    <span class="keyword">@autoreleasepool</span> &#123;</span><br><span class="line">        <span class="built_in">NSObject</span> *objc = [[<span class="built_in">NSObject</span> alloc] init];</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@&quot;objc对象类型占用的内存大小：%lu&quot;</span>,<span class="keyword">sizeof</span>(objc));</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@&quot;objc对象实际占用的内存大小：%lu&quot;</span>,class_getInstanceSize([objc <span class="keyword">class</span>]));</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@&quot;objc对象实际分配的内存大小：%lu&quot;</span>,malloc_size((__bridge <span class="keyword">const</span> <span class="type">void</span>*)(objc)));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>输出结果分别为</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">objc对象类型占用的内存大小：<span class="number">8</span></span><br><span class="line">objc对象实际占用的内存大小：<span class="number">8</span></span><br><span class="line">objc对象实际分配的内存大小：<span class="number">16</span></span><br></pre></td></tr></table></figure><p>由上述结果我们可得出并验证：</p><ul><li>sizeof：<code>计算类型占用的内存大小</code>，其中可以放基本数据类型、对象、指针，对于类似于int这样的基本数据而言，sizeof获取的就是数据类型占用的内存大小，不同的数据类型所占用的内存大小是不一样的，而对于类似于NSObject定义的实例对象而言，其对象类型的本质就是一个结构体（即 struct objc_object）的指针，所以sizeof(objc)打印的是对象objc的指针大小，我们知道一个指针的内存大小是8，所以sizeof(objc) 打印是 8。(注意：这里的8字节与isa指针一点关系都没有!)，对于指针而言，sizeof打印的就是8，因为一个指针的内存大小是8，</li><li>class_getInstanceSize：<code>计算对象实际占用的内存大小</code>，这个需要依据类的属性而变化，如果自定义类没有自定义属性，仅仅只是继承自NSObject，则类的实例对象实际占用的内存大小是8，可以简单理解为8字节对齐</li><li>malloc_size：<code>计算对象实际分配的内存大小</code>，这个是由系统完成的，可以从上面的打印结果看出，实际分配的和实际占用的内存大小并不相等，具体可参考并了解源码分析中的16字节对齐算法来解释这个问题</li></ul><h3 id="结构体内存对齐"><a href="#结构体内存对齐" class="headerlink" title="结构体内存对齐"></a>结构体内存对齐</h3><p>下面我们开始进入正题：内存对齐原理的探究<br>众所周知，结构体和类的内存对齐方式类似，接下来，我们通过两个结构体来展开<code>内存对齐原理</code>的探究：</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1、定义两个结构体</span></span><br><span class="line"><span class="keyword">struct</span> Mystruct1&#123;</span><br><span class="line">    <span class="type">char</span> a;     <span class="comment">//1字节</span></span><br><span class="line">    <span class="type">double</span> b;   <span class="comment">//8字节</span></span><br><span class="line">    <span class="type">int</span> c;      <span class="comment">//4字节</span></span><br><span class="line">    <span class="type">short</span> d;    <span class="comment">//2字节</span></span><br><span class="line">&#125;Mystruct1;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> Mystruct2&#123;</span><br><span class="line">    <span class="type">double</span> b;   <span class="comment">//8字节</span></span><br><span class="line">    <span class="type">int</span> c;      <span class="comment">//4字节</span></span><br><span class="line">    <span class="type">short</span> d;    <span class="comment">//2字节</span></span><br><span class="line">    <span class="type">char</span> a;     <span class="comment">//1字节</span></span><br><span class="line">&#125;Mystruct2;</span><br><span class="line"></span><br><span class="line"><span class="comment">//计算 结构体占用的内存大小</span></span><br><span class="line"><span class="built_in">NSLog</span>(<span class="string">@&quot;%lu-%lu&quot;</span>,<span class="keyword">sizeof</span>(Mystruct1),<span class="keyword">sizeof</span>(Mystruct2));</span><br></pre></td></tr></table></figure><p>上述两个结构体，通过控制台打印输出分别得到sizeof(Mystruct1)&#x3D;24，sizeof(Mystruct2)&#x3D;16，那么两个变量及变量类型都相同的结构体，仅仅是排列顺序不同，他们所占用的内存大小为什么不一样呢？这就是我们所要探究的<code>内存字节对齐</code>现象<br>通过文章开头<code>内存对齐原则</code>计算MyStruct1的内存大小，详解过程如下：</p><ul><li>变量a：占1个字节，从0开始，此时min（0，1），即 0 存储 a</li><li>变量b：占8个字节，从1开始，此时min（1，8），1不能整除8，继续往后移动，知道min（8，8），从8开始，即 8-15 存储 b</li><li>变量c：占4个字节，从16开始，此时min（16，4），16可以整除4，即 16-19 存储 c</li><li>变量d：占2个字节，从20开始，此时min(20, 2)，20可以整除2，即20-21 存储 d</li></ul><p>因此MyStruct1的需要的内存大小为 15字节，而MyStruct1中最大变量的字节数为8，所以 MyStruct1 实际的内存大小必须是 8 的整数倍，21向上取整到24，主要是因为24是8的整数倍，所以 sizeof(MyStruct1) 的结果是 24</p><p>根据<code>内存对齐规则</code>计算MyStruct2的内存大小，详解过程如下：</p><ul><li>变量b：占8个字节，从0开始，此时min（0，8），即 0-7 存储 b</li><li>变量c：占4个字节，从8开始，此时min（8，4），8可以整除4，即 8-11 存储 c</li><li>变量d：占2个字节，从12开始，此时min(12, 2)，12可以整除2，即12-13 存储 d</li><li>变量a：占1个字节，从14开始，此时min（14，1），即 14 存储 a</li></ul><p>因此MyStruct2的需要的内存大小为 15字节，而MyStruct1中最大变量的字节数为8，所以 MyStruct2 实际的内存大小必须是 8 的整数倍，15向上取整到16，主要是因为16是8的整数倍，所以 sizeof(MyStruct2) 的结果是 16</p><p><img src="/./2022/04/20/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8603%EF%BC%9A%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/struct.jpg" alt="struct"></p><h3 id="结构体嵌套结构体"><a href="#结构体嵌套结构体" class="headerlink" title="结构体嵌套结构体"></a>结构体嵌套结构体</h3><p>上面的两个结构体只是简单的定义数据成员，下面来一个比较复杂的，结构体中嵌套结构体的内存大小计算情况</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//1、结构体嵌套结构体</span></span><br><span class="line"><span class="keyword">struct</span> Mystruct3&#123;</span><br><span class="line">    <span class="type">double</span> b;   <span class="comment">//8字节</span></span><br><span class="line">    <span class="type">int</span> c;      <span class="comment">//4字节</span></span><br><span class="line">    <span class="type">short</span> d;    <span class="comment">//2字节</span></span><br><span class="line">    <span class="type">char</span> a;     <span class="comment">//1字节</span></span><br><span class="line">    <span class="keyword">struct</span> Mystruct2 str; </span><br><span class="line">&#125;Mystruct3;</span><br><span class="line"></span><br><span class="line"><span class="comment">//2、打印 Mystruct3 的内存大小</span></span><br><span class="line"><span class="built_in">NSLog</span>(<span class="string">@&quot;Mystruct3内存大小：%lu&quot;</span>, <span class="keyword">sizeof</span>(Mystruct3));</span><br><span class="line"><span class="built_in">NSLog</span>(<span class="string">@&quot;Mystruct3中结构体成员内存大小：%lu&quot;</span>, <span class="keyword">sizeof</span>(Mystruct3.str));</span><br></pre></td></tr></table></figure><p>分析Mystruct3的内存计算<br>根据内存对齐规则，来一步一步分析Mystruct3内存大小的计算过程</p><ul><li>变量b：占8个字节，从0开始，此时min（0，8），即 0-7 存储 b</li><li>变量c：占4个字节，从8开始，此时min（8，4），8可以整除4，即 8-11 存储 c</li><li>变量d：占2个字节，从12开始，此时min(12, 2)，20可以整除2，即12-13 存储 d</li><li>变量a：占1个字节，从14开始，此时min（14，1），即 14 存储 a</li><li>结构体成员str：str是一个结构体，根据内存对齐原则二，结构体成员要从其内部最大成员大小的整数倍开始存储，而MyStruct2中最大的成员大小为8，所以str要从8的整数倍开始，当前是从15开始，所以不符合要求，需要往后移动到16，16是8的整数倍，符合内存对齐原则，所以 16-31 存储 str</li></ul><p>因此MyStruct3的需要的内存大小为 32字节，而MyStruct3中最大变量为str, 其最大成员内存字节数为8，根据内存对齐原则，所以 MyStruct3 实际的内存大小必须是 8 的整数倍，32正好是8的整数倍，所以 sizeof(MyStruct3) 的结果是 32</p><p>其内存存储情况如下图所示<br><img src="/./2022/04/20/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8603%EF%BC%9A%E5%86%85%E5%AD%98%E5%AF%B9%E9%BD%90%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/struct_2.jpg" alt="嵌套struct"></p>]]></content>
    
    
    <summary type="html">&lt;h3 id=&quot;前言&quot;&gt;&lt;a href=&quot;#前言&quot; class=&quot;headerlink&quot; title=&quot;前言&quot;&gt;&lt;/a&gt;前言&lt;/h3&gt;&lt;p&gt;在开始探究内存对齐原理之前，我们先来两个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;内存对齐原则是什么？&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;数据成员对齐规则：结构体（struct）或联合体（union）的数据成员，第一个数据成员放在 offset 为 0 的地方，以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小（只要该成员有子成员，比如说数组、结构体等）的整数倍开始（比如int为4字节，则要从4的整数倍地址开始存储）&lt;/li&gt;
&lt;li&gt;结构体作为成员：如果一个结构里有某些结构体成员，则结构体成员要从其内部最大元素大小的整数倍地址开始存储（strcut a里存有 struct b，b里有结构体char，int 等，那么b应该从8的整数倍开始存储）&lt;/li&gt;
&lt;li&gt;结构体的总大小，也就是sizeof的结果，必须是其内部最大成员的整数倍，不足的需要补齐&lt;/li&gt;&lt;/ul&gt;</summary>
    
    
    
    <category term="iOS底层原理" scheme="https://shaogithub.github.io/categories/iOS%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    
    
    <category term="iOS" scheme="https://shaogithub.github.io/tags/iOS/"/>
    
    <category term="iOS底层原理" scheme="https://shaogithub.github.io/tags/iOS%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>iOS-底层原理02：alloc&amp;init&amp;new分别做了什么</title>
    <link href="https://shaogithub.github.io/2022/04/17/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8602%EF%BC%9Aalloc-init-new%E5%88%86%E5%88%AB%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88/"/>
    <id>https://shaogithub.github.io/2022/04/17/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8602%EF%BC%9Aalloc-init-new%E5%88%86%E5%88%AB%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88/</id>
    <published>2022-04-17T02:44:31.000Z</published>
    <updated>2022-04-17T04:12:17.989Z</updated>
    
    <content type="html"><![CDATA[<p>在我们的日常开发的过程中经常会使用到alloc，init，new，这些方法，但是这些方法又是如何实现的呢？在他们当中又做了哪些事情呢？下面我们先来看一个例子：</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">GJPerson *objc1 = [GJPerson alloc];</span><br><span class="line">GJPerson *objc2 = [objc1 init];</span><br><span class="line">GJPerson *objc3 = [objc1 init];</span><br><span class="line"><span class="built_in">NSLog</span>(<span class="string">@&quot;%@ - %p - %p&quot;</span>, objc1, objc1, &amp;objc1);</span><br><span class="line"><span class="built_in">NSLog</span>(<span class="string">@&quot;%@ - %p - %p&quot;</span>, objc2, objc2, &amp;objc2);</span><br><span class="line"><span class="built_in">NSLog</span>(<span class="string">@&quot;%@ - %p - %p&quot;</span>, objc3, objc3, &amp;objc3);</span><br></pre></td></tr></table></figure><p>以上3条输出语句分别输出了3个对象的<strong>内容、内存地址、指针地址</strong>，他们的值又会是什么呢？是否相同呢？</p><span id="more"></span><p>验证结果如下图：<br><img src="/./2022/04/17/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8602%EF%BC%9Aalloc-init-new%E5%88%86%E5%88%AB%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88/%E9%AA%8C%E8%AF%81%E7%BB%93%E6%9E%9C.jpg" alt="验证结果"></p><p>从验证结果可知，3个对象指向的是<code>同一内存空间</code>，所以其<code>内容</code>和<code>内存地址</code>都是<strong>相同</strong>的，但是<code>指针地址</code>是<strong>不同的</strong><br>从而我们可以初步的推断出，alloc开辟了内存空间，init将指针指向alloc开辟的内存空间中！</p><p>下面我们就来深入的了解一下alloc，init，new ~</p><h2 id="alloc源码探究"><a href="#alloc源码探究" class="headerlink" title="alloc源码探究"></a>alloc源码探究</h2><blockquote><p>准备工作：<br>下载<a href="https://opensource.apple.com/tarballs/">objc4源码</a><br>编译源码，可自行进行百度、google、github，网上有详细的编译教程以及可编译程序，就不多加赘述了</p></blockquote><p>alloc + init 整体源码的执行流程如下图：<br><img src="/./2022/04/17/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8602%EF%BC%9Aalloc-init-new%E5%88%86%E5%88%AB%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88/alloc%E6%BA%90%E7%A0%81%E6%B5%81%E7%A8%8B%E5%9B%BE.jpg" alt="alloc源码流程图"></p><p>通过断点调试源码可知，alloc实现主要分为以下几个步骤：</p><h3 id="第一步：alloc-方法"><a href="#第一步：alloc-方法" class="headerlink" title="第一步：alloc 方法"></a>第一步：alloc 方法</h3><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">+ (<span class="type">id</span>)alloc &#123;</span><br><span class="line">    <span class="keyword">return</span> _objc_rootAlloc(<span class="keyword">self</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="第二步：-objc-rootAlloc-方法"><a href="#第二步：-objc-rootAlloc-方法" class="headerlink" title="第二步：_objc_rootAlloc 方法"></a>第二步：_objc_rootAlloc 方法</h3><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">id</span></span><br><span class="line">_objc_rootAlloc(Class cls)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> callAlloc(cls, <span class="literal">false</span><span class="comment">/*checkNil*/</span>, <span class="literal">true</span><span class="comment">/*allocWithZone*/</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="第三步：callAlloc-方法"><a href="#第三步：callAlloc-方法" class="headerlink" title="第三步：callAlloc 方法"></a>第三步：callAlloc 方法</h3><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> ALWAYS_INLINE <span class="type">id</span></span><br><span class="line">callAlloc(Class cls, <span class="type">bool</span> checkNil, <span class="type">bool</span> allocWithZone=<span class="literal">false</span>)<span class="comment">// alloc 源码 第三步</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="meta">#<span class="keyword">if</span> __OBJC2__ <span class="comment">//有可用的编译器优化</span></span></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">fastpath slowpath参考链接：https://www.jianshu.com/p/536824702ab6</span></span><br><span class="line"><span class="comment">checkNil 为false，!cls 也为false ，所以slowpath 为 false，假值判断不会走到if里面，即不会返回nil</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">if</span> (slowpath(checkNil &amp;&amp; !cls)) <span class="keyword">return</span> <span class="literal">nil</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 判断一个类是否有自定义的 +allocWithZone 实现，没有则走到if里面的实现</span></span><br><span class="line">    <span class="keyword">if</span> (fastpath(!cls-&gt;ISA()-&gt;hasCustomAWZ())) &#123;</span><br><span class="line">        <span class="keyword">return</span> _objc_rootAllocWithZone(cls, <span class="literal">nil</span>);</span><br><span class="line">    &#125;</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// No shortcuts available. // 没有可用的编译器优化</span></span><br><span class="line">    <span class="keyword">if</span> (allocWithZone) &#123;</span><br><span class="line">        <span class="keyword">return</span> ((<span class="type">id</span>(*)(<span class="type">id</span>, SEL, <span class="keyword">struct</span> _NSZone *))objc_msgSend)(cls, <span class="keyword">@selector</span>(allocWithZone:), <span class="literal">nil</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ((<span class="type">id</span>(*)(<span class="type">id</span>, SEL))objc_msgSend)(cls, <span class="keyword">@selector</span>(alloc));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="第四步：通过断点调试执行了-objc-rootAllocWithZone方法，这部分是alloc源码的核心操作，由下面的流程图及源码可知，该方法的实现主要分为三部分"><a href="#第四步：通过断点调试执行了-objc-rootAllocWithZone方法，这部分是alloc源码的核心操作，由下面的流程图及源码可知，该方法的实现主要分为三部分" class="headerlink" title="第四步：通过断点调试执行了_objc_rootAllocWithZone方法，这部分是alloc源码的核心操作，由下面的流程图及源码可知，该方法的实现主要分为三部分"></a>第四步：通过断点调试执行了_objc_rootAllocWithZone方法，这部分是alloc源码的核心操作，由下面的流程图及源码可知，该方法的实现主要分为三部分</h3><ul><li>cls-&gt;instanceSize：计算需要开辟的内存空间大小</li><li>calloc：申请内存，返回地址指针</li><li>obj-&gt;initInstanceIsa：将 类 与 isa 关联<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> ALWAYS_INLINE <span class="type">id</span></span><br><span class="line">_class_createInstanceFromZone(Class cls, size_t extraBytes, <span class="type">void</span> *zone,</span><br><span class="line">                              <span class="type">int</span> construct_flags = OBJECT_CONSTRUCT_NONE,</span><br><span class="line">                              <span class="type">bool</span> cxxConstruct = <span class="literal">true</span>,</span><br><span class="line">                              size_t *outAllocatedSize = <span class="literal">nil</span>)<span class="comment">// alloc 源码 第五步</span></span><br><span class="line">&#123;</span><br><span class="line">    ASSERT(cls-&gt;isRealized()); <span class="comment">//检查是否已经实现</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Read class&#x27;s info bits all at once for performance</span></span><br><span class="line">    <span class="comment">//一次性读取类的位信息以提高性能</span></span><br><span class="line">    <span class="type">bool</span> hasCxxCtor = cxxConstruct &amp;&amp; cls-&gt;hasCxxCtor();</span><br><span class="line">    <span class="type">bool</span> hasCxxDtor = cls-&gt;hasCxxDtor();</span><br><span class="line">    <span class="type">bool</span> fast = cls-&gt;canAllocNonpointer();</span><br><span class="line">    size_t size;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//计算需要开辟的内存大小，传入的extraBytes 为 0</span></span><br><span class="line">    size = cls-&gt;instanceSize(extraBytes);</span><br><span class="line">    <span class="keyword">if</span> (outAllocatedSize) *outAllocatedSize = size;</span><br><span class="line"></span><br><span class="line">    <span class="type">id</span> obj;</span><br><span class="line">    <span class="keyword">if</span> (zone) &#123;</span><br><span class="line">        obj = (<span class="type">id</span>)malloc_zone_calloc((malloc_zone_t *)zone, <span class="number">1</span>, size);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">//申请内存</span></span><br><span class="line">        obj = (<span class="type">id</span>)calloc(<span class="number">1</span>, size);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (slowpath(!obj)) &#123;</span><br><span class="line">        <span class="keyword">if</span> (construct_flags &amp; OBJECT_CONSTRUCT_CALL_BADALLOC) &#123;</span><br><span class="line">            <span class="keyword">return</span> _objc_callBadAllocHandler(cls);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nil</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!zone &amp;&amp; fast) &#123;</span><br><span class="line">        <span class="comment">//将 cls类 与 obj指针（即isa） 关联</span></span><br><span class="line">        obj-&gt;initInstanceIsa(cls, hasCxxDtor);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// Use raw pointer isa on the assumption that they might be</span></span><br><span class="line">        <span class="comment">// doing something weird with the zone or RR.</span></span><br><span class="line">        obj-&gt;initIsa(cls);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (fastpath(!hasCxxCtor)) &#123;</span><br><span class="line">        <span class="keyword">return</span> obj;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;</span><br><span class="line">    <span class="keyword">return</span> object_cxxConstructFromClass(obj, cls, construct_flags);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="cls-gt-instanceSize：计算所需内存大小"><a href="#cls-gt-instanceSize：计算所需内存大小" class="headerlink" title="cls-&gt;instanceSize：计算所需内存大小"></a>cls-&gt;instanceSize：计算所需内存大小</h4><img src="/./2022/04/17/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8602%EF%BC%9Aalloc-init-new%E5%88%86%E5%88%AB%E5%81%9A%E4%BA%86%E4%BB%80%E4%B9%88/%E8%AE%A1%E7%AE%97%E6%89%80%E9%9C%80%E5%86%85%E5%AD%98%E5%A4%A7%E5%B0%8F.jpg" alt="计算所需内存大小"></li><li>instanceSize的源码实现<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">size_t instanceSize(size_t extraBytes) <span class="keyword">const</span> &#123;</span><br><span class="line">    <span class="comment">//编译器快速计算内存大小</span></span><br><span class="line">    <span class="keyword">if</span> (fastpath(cache.hasFastInstanceSize(extraBytes))) &#123;</span><br><span class="line">        <span class="keyword">return</span> cache.fastInstanceSize(extraBytes);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 计算类中所有属性的大小 + 额外的字节数0</span></span><br><span class="line">    size_t size = alignedInstanceSize() + extraBytes;</span><br><span class="line">    <span class="comment">// CF requires all objects be at least 16 bytes.</span></span><br><span class="line">    <span class="comment">//如果size 小于 16，最小取16</span></span><br><span class="line">    <span class="keyword">if</span> (size &lt; <span class="number">16</span>) size = <span class="number">16</span>;</span><br><span class="line">    <span class="keyword">return</span> size;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li>fastInstanceSize的源码实现<figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">size_t fastInstanceSize(size_t extra) <span class="keyword">const</span></span><br><span class="line">&#123;</span><br><span class="line">    ASSERT(hasFastInstanceSize(extra));</span><br><span class="line"></span><br><span class="line">    <span class="comment">//Gcc的内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数，如果参数EXP 的值是常数，函数返回 1，否则返回 0</span></span><br><span class="line">    <span class="keyword">if</span> (__builtin_constant_p(extra) &amp;&amp; extra == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> _flags &amp; FAST_CACHE_ALLOC_MASK16;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        size_t size = _flags &amp; FAST_CACHE_ALLOC_MASK;</span><br><span class="line">        <span class="comment">// remove the FAST_CACHE_ALLOC_DELTA16 that was added</span></span><br><span class="line">        <span class="comment">// by setFastInstanceSize</span></span><br><span class="line">        <span class="comment">//删除由setFastInstanceSize添加的FAST_CACHE_ALLOC_DELTA16 8个字节</span></span><br><span class="line">        <span class="keyword">return</span> align16(size + extra - FAST_CACHE_ALLOC_DELTA16);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>align16内存字节对齐原则<br>&#x2F;&#x2F;16字节对齐算法<br>static inline size_t align16(size_t x) {<br>return (x + size_t(15)) &amp; ~size_t(15);<br>}</p></blockquote></li></ul><h4 id="内存字节对齐原则"><a href="#内存字节对齐原则" class="headerlink" title="内存字节对齐原则"></a>内存字节对齐原则</h4><p>在解释为什么需要16字节对齐之前，首先需要了解内存字节对齐的原则，主要有以下三点</p><ul><li>数据成员对齐规则：struct 或者 union 的数据成员，第一个数据成员放在offset为0的地方，以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小（只要该成员有子成员，比如数据、结构体等）的整数倍开始（例如int在32位机中是4字节，则要从4的整数倍地址开始存储）</li><li>数据成员为结构体：如果一个结构里有某些结构体成员，则结构体成员要从其内部最大元素大小的整数倍地址开始存储（例如：struct a里面存有struct b，b里面有char、int、double等元素，则b应该从8的整数倍开始存储）</li><li>结构体的整体对齐规则：结构体的总大小，即sizeof的结果，必须是其内部做大成员的整数倍，不足的要补齐</li></ul><h4 id="为什么需要16字节对齐"><a href="#为什么需要16字节对齐" class="headerlink" title="为什么需要16字节对齐"></a>为什么需要16字节对齐</h4><p>需要字节对齐的原因，有以下几点：</p><ul><li>通常内存是由一个个字节组成的，cpu在存取数据时，并不是以字节为单位存储，而是以块为单位存取，块的大小为内存存取力度。频繁存取字节未对齐的数据，会极大降低cpu的性能，所以可以通过减少存取次数来降低cpu的开销</li><li>16字节对齐，是由于在一个对象中，第一个属性isa占8字节，当然一个对象肯定还有其他属性，当无属性时，会预留8字节，即16字节对齐，如果不预留，相当于这个对象的isa和其他对象的isa紧挨着，容易造成访问混乱</li><li>16字节对齐后，可以加快CPU读取速度，同时使访问更安全，不会产生访问混乱的情况</li></ul><h4 id="calloc：申请内存，返回地址指针"><a href="#calloc：申请内存，返回地址指针" class="headerlink" title="calloc：申请内存，返回地址指针"></a>calloc：申请内存，返回地址指针</h4><p>此时并没有与obj对象进行关联，只是返回了地址指针</p><h4 id="obj-gt-initInstanceIsa：类与isa关联"><a href="#obj-gt-initInstanceIsa：类与isa关联" class="headerlink" title="obj-&gt;initInstanceIsa：类与isa关联"></a>obj-&gt;initInstanceIsa：类与isa关联</h4><p>将上述得到的地址指针与obj进行关联</p><p>到此alloc执行就已经结束了 ~</p><hr><h2 id="init-源码探索"><a href="#init-源码探索" class="headerlink" title="init 源码探索"></a>init 源码探索</h2><p>类方法实现init</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">+ (<span class="type">id</span>)init &#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="type">id</span>)<span class="keyword">self</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里的init是一个构造方法 ，是通过工厂设计（工厂方法模式）,主要是用于给用户提供构造方法入口。这里能使用id强转的原因，主要还是因为 内存字节对齐后，可以使用类型强转为你所需的类型</p><h2 id="new-源码探索"><a href="#new-源码探索" class="headerlink" title="new 源码探索"></a>new 源码探索</h2><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">+ (<span class="type">id</span>)new &#123;</span><br><span class="line">    <span class="keyword">return</span> [callAlloc(<span class="keyword">self</span>, <span class="literal">false</span><span class="comment">/*checkNil*/</span>) init];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>从以上代码可以看出，<code>new</code>方法实际上等价与<code>[[xxx alloc] init]</code>，鉴于开发过程中通常会重写init方法做一些自定义的操作，所以不建议使用new方法</p><hr><blockquote><p>注：<br>1.如果子类没有重写父类的init，new会调用父类的init方法<br>2.如果子类重写了父类的init，new会调用子类重写的init方法<br>3.如果使用 alloc + 自定义的init，可以帮助我们自定义初始化操作，例如传入一些子类所需参数等，最终也会走到父类的init，相比new而言，扩展性更好，更灵活。</p></blockquote>]]></content>
    
    
    <summary type="html">&lt;p&gt;在我们的日常开发的过程中经常会使用到alloc，init，new，这些方法，但是这些方法又是如何实现的呢？在他们当中又做了哪些事情呢？下面我们先来看一个例子：&lt;/p&gt;
&lt;figure class=&quot;highlight objc&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;4&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;6&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;GJPerson *objc1 = [GJPerson alloc];&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;GJPerson *objc2 = [objc1 init];&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;GJPerson *objc3 = [objc1 init];&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;NSLog&lt;/span&gt;(&lt;span class=&quot;string&quot;&gt;@&amp;quot;%@ - %p - %p&amp;quot;&lt;/span&gt;, objc1, objc1, &amp;amp;objc1);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;NSLog&lt;/span&gt;(&lt;span class=&quot;string&quot;&gt;@&amp;quot;%@ - %p - %p&amp;quot;&lt;/span&gt;, objc2, objc2, &amp;amp;objc2);&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;built_in&quot;&gt;NSLog&lt;/span&gt;(&lt;span class=&quot;string&quot;&gt;@&amp;quot;%@ - %p - %p&amp;quot;&lt;/span&gt;, objc3, objc3, &amp;amp;objc3);&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;
&lt;p&gt;以上3条输出语句分别输出了3个对象的&lt;strong&gt;内容、内存地址、指针地址&lt;/strong&gt;，他们的值又会是什么呢？是否相同呢？&lt;/p&gt;</summary>
    
    
    
    <category term="iOS底层原理" scheme="https://shaogithub.github.io/categories/iOS%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    
    
    <category term="iOS" scheme="https://shaogithub.github.io/tags/iOS/"/>
    
    <category term="iOS底层原理" scheme="https://shaogithub.github.io/tags/iOS%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>iOS-底层原理01：LLDB调试命令&amp;源码探索方式</title>
    <link href="https://shaogithub.github.io/2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/"/>
    <id>https://shaogithub.github.io/2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/</id>
    <published>2022-04-16T15:31:17.000Z</published>
    <updated>2022-04-17T02:38:50.854Z</updated>
    
    <content type="html"><![CDATA[<blockquote><ol><li>在日常开发中我们经常会用到<code>LLDB调试</code>，比如：p xxx，po xxx，bt等等，这些调试命令的作用都是什么呢？</li><li><code>源码探索</code>对于开发来说也是一件必须要掌握的事情，源码探索的方法又有哪些呢？</li></ol></blockquote><p>下面针对这两点，我们将一一进行解释说明！</p><span id="more"></span><h2 id="LLDB常用调试命令集合"><a href="#LLDB常用调试命令集合" class="headerlink" title="LLDB常用调试命令集合"></a>LLDB常用调试命令集合</h2><h3 id="1-p和po命令"><a href="#1-p和po命令" class="headerlink" title="1. p和po命令"></a>1. p和po命令</h3><ul><li>p 命令： print 命令的简写，使用p 命令可以查看基本数据类型的值；如果使用p命令查看的是对象，那么只会返回对象的指针地址。 p命令后面除了可以接变量、常量，还可以接表达式。</li><li>po 命令：print object的缩写，可以理解为打印对象。功能与p命令类似，也可以打印常量、变量，打印表达式返回的对象等。<br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/po%E5%91%BD%E4%BB%A4.jpg" alt="LLDB-p&amp;po命令"><blockquote><p>p 和 po 的区别在于使用 po 只会输出对应的值，而 p 则会返回值的类型以及命令结果的引用名。</p></blockquote></li></ul><p>ps: 使用p做进制转换</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//默认打印为10进制</span></span><br><span class="line">(lldb) p <span class="number">20</span></span><br><span class="line">(<span class="type">int</span>) $<span class="number">0</span> = <span class="number">20</span></span><br><span class="line"><span class="comment">//转16进制</span></span><br><span class="line">(lldb) p/x <span class="number">10</span></span><br><span class="line">(<span class="type">int</span>) $<span class="number">1</span> = <span class="number">0x0000000a</span></span><br><span class="line"><span class="comment">//转8进制</span></span><br><span class="line">(lldb) p/o <span class="number">10</span></span><br><span class="line">(<span class="type">int</span>) $<span class="number">2</span> = <span class="number">012</span></span><br><span class="line"><span class="comment">//转二进制</span></span><br><span class="line">(lldb) p/t <span class="number">10</span></span><br><span class="line">(<span class="type">int</span>) $<span class="number">3</span> = <span class="number">0</span>b00000000000000000000000000001010</span><br><span class="line"><span class="comment">//字符转10进制数字</span></span><br><span class="line">(lldb) p/d <span class="string">&#x27;A&#x27;</span></span><br><span class="line">(<span class="type">char</span>) $<span class="number">4</span> = <span class="number">65</span></span><br><span class="line"><span class="comment">//10进制数字转字符</span></span><br><span class="line">(lldb) p/c <span class="number">66</span></span><br><span class="line">(<span class="type">int</span>) $<span class="number">5</span> = B\<span class="number">0</span>\<span class="number">0</span>\<span class="number">0</span></span><br></pre></td></tr></table></figure><h3 id="2-bt命令（thread-backtrace堆栈打印简写）"><a href="#2-bt命令（thread-backtrace堆栈打印简写）" class="headerlink" title="2. bt命令（thread backtrace堆栈打印简写）"></a>2. bt命令（thread backtrace堆栈打印简写）</h3><ul><li>bt命令可以打印出线程的堆栈信息，bt命令是打印当前线程的堆栈信息，如下图所示。该信息比左侧的Debug Navigator 看到的还要详细一些。如果嫌堆栈打印太长，可以加一个值限制，如bt 10。<br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/bt%E5%91%BD%E4%BB%A4.jpg" alt="bt命令"></li><li>bt all 命令可以打印所有线程的堆栈信息。<br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/bt-all%E5%91%BD%E4%BB%A4.jpg" alt="bt-all命令"></li></ul><h3 id="3-内存读取命令"><a href="#3-内存读取命令" class="headerlink" title="3. 内存读取命令"></a>3. 内存读取命令</h3><ul><li>x命令就是memory read内存读取并打印的作用， x是读取内存的命令<br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/x%E5%91%BD%E4%BB%A4.jpg" alt="x命令"></li><li>x&#x2F;4gx中第一个x是读取内存命令，后面的g是每次读取8字节，x的意思是16进制显示结果，4表示连续打印4段。</li><li>对于g，常用的大小格式为b对应byte 1字节，h对应half word 2字节，w对应word 4字节，g对应giant word 8字节</li><li>对于x，我们还可以用o对应8机制，b对应2进制,x对应16进制,f对应浮点，d对应10进制。<br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/x-4gx%E5%91%BD%E4%BB%A4.jpg" alt="x-4gx命令"></li></ul><h3 id="4-thread-list命令"><a href="#4-thread-list命令" class="headerlink" title="4. thread list命令"></a>4. thread list命令</h3><ul><li>用于列出所有线程，如下图所示，其中星号(*)表示thread#1为当前线程。<br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/thread-list%E5%91%BD%E4%BB%A4.jpg" alt="thread-list命令"></li></ul><h3 id="5-待续。。。"><a href="#5-待续。。。" class="headerlink" title="5. 待续。。。"></a>5. 待续。。。</h3><hr><h2 id="源码探索的的三种方法"><a href="#源码探索的的三种方法" class="headerlink" title="源码探索的的三种方法"></a>源码探索的的三种方法</h2><ul><li>打<code>符号断点</code>方式调试流程</li><li>通过按住<code>control</code>+<code>step into</code>按钮逐步进入调试</li><li>汇编源码跟流程</li></ul><h3 id="1-打符号断点方式调试流程"><a href="#1-打符号断点方式调试流程" class="headerlink" title="1. 打符号断点方式调试流程"></a>1. 打<code>符号断点</code>方式调试流程</h3><p>选择编译器调试中的<code>Symbolic Breakpoint</code>断点调试<br>例如：探索alloc方法，添加<code>Symbolic Breakpoint</code>断点，即可查看到alloc源码位于libobjc.A.dylib库中，如下图：<br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/alloc%E6%96%B9%E6%B3%95%E6%8E%A2%E7%A9%B6.jpg" alt="alloc方法探究"></p><h3 id="2-通过按住control-step-into按钮逐步进入调试"><a href="#2-通过按住control-step-into按钮逐步进入调试" class="headerlink" title="2. 通过按住control+step into按钮逐步进入调试"></a>2. 通过按住<code>control</code>+<code>step into</code>按钮逐步进入调试</h3><p>在相应的alloc处打上断点，当执行到断点处时，按下<code>control</code>+<code>step into</code>即可逐步调试<br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/stepinto%E8%B0%83%E8%AF%95.jpg" alt="stepinto调试"><br><img src="/./2022/04/16/iOS-%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%8601%EF%BC%9ALLDB%E8%B0%83%E8%AF%95%E5%91%BD%E4%BB%A4-%E6%BA%90%E7%A0%81%E6%8E%A2%E7%B4%A2%E6%96%B9%E5%BC%8F/stepinto%E8%B0%83%E8%AF%952.jpg" alt="stepinto调试2"><br>调试结果依然可以看到alloc源码位于libobjc.A.dylib库中</p><h3 id="3-汇编源码跟流程"><a href="#3-汇编源码跟流程" class="headerlink" title="3. 汇编源码跟流程"></a>3. 汇编源码跟流程</h3><p>xcode 工具栏 选择 Debug –&gt; Debug Workflow –&gt; Always Show Disassembly,这个 选项表示 始终显示反汇编 ，即 通过汇编 跟流程<br>调试结果同方法2，依然可以看到<code>objc_alloc</code>，从而得到alloc源码位于libobjc.A.dylib库中</p><hr><blockquote><p>ps:注意（以下是Apple 提供的源码下载地址）：<br>1、<a href="https://opensource.apple.com/">Apple 所有开源源码汇总地址</a>，根据相应的版本查找对应的源码，以<code>mac 10.15为例: macOS --&gt; 10.15 --&gt; 选择10.15 --&gt; 搜索 objc</code><br>2、<a href="https://opensource.apple.com/tarballs/">Apple 比较直接的源码下载地址</a>，直接搜索想要下载的源码名称即可，例如objc：直接搜索 <code>objc --&gt; objc4/ --&gt; 选择相应的objc的版本</code></p></blockquote>]]></content>
    
    
    <summary type="html">&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;在日常开发中我们经常会用到&lt;code&gt;LLDB调试&lt;/code&gt;，比如：p xxx，po xxx，bt等等，这些调试命令的作用都是什么呢？&lt;/li&gt;
&lt;li&gt;&lt;code&gt;源码探索&lt;/code&gt;对于开发来说也是一件必须要掌握的事情，源码探索的方法又有哪些呢？&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面针对这两点，我们将一一进行解释说明！&lt;/p&gt;</summary>
    
    
    
    <category term="iOS底层原理" scheme="https://shaogithub.github.io/categories/iOS%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    
    
    <category term="iOS" scheme="https://shaogithub.github.io/tags/iOS/"/>
    
    <category term="iOS底层原理" scheme="https://shaogithub.github.io/tags/iOS%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86/"/>
    
  </entry>
  
  <entry>
    <title>私有pod库创建</title>
    <link href="https://shaogithub.github.io/2022/04/02/custom-repo-ios/"/>
    <id>https://shaogithub.github.io/2022/04/02/custom-repo-ios/</id>
    <published>2022-04-02T14:14:10.000Z</published>
    <updated>2022-04-02T14:57:06.355Z</updated>
    
    <content type="html"><![CDATA[<h3 id="创建私有pod库："><a href="#创建私有pod库：" class="headerlink" title="创建私有pod库："></a>创建私有pod库：</h3><p>创建公有Pod库或者私有Pod库, 实际上原理是一样的, 都是基于git服务和repo协议, 不一样的是, 两者的版本索引查询方式不一样, 公有库的podspec由CocoaPods&#x2F;Specs管理, 而内部私有使用的pod库需要自己建立一个仓库来管理podspec.</p><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建pod库</span></span><br><span class="line"><span class="comment">// 例如：pod lib create GJNotifyView</span></span><br><span class="line">pod lib create [repo-name]</span><br></pre></td></tr></table></figure><span id="more"></span><h4 id="回车之后，终端会询问你几个哲学的问题"><a href="#回车之后，终端会询问你几个哲学的问题" class="headerlink" title="回车之后，终端会询问你几个哲学的问题"></a>回车之后，终端会询问你几个哲学的问题</h4><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"># 选择编程语言</span><br><span class="line">What language <span class="keyword">do</span> you want to use?? [ Swift / ObjC ]</span><br><span class="line">&gt; Objc  </span><br><span class="line"></span><br><span class="line"># 在你的项目中是否创建一个demo工程，为了方便测试，我选择了Yes</span><br><span class="line">Would you like to include a demo application with your library? [ Yes / No ]</span><br><span class="line"> &gt; Yes  </span><br><span class="line"></span><br><span class="line"># 测试框架选择哪一个</span><br><span class="line">Which testing frameworks will you use? [ Specta / Kiwi / None ]</span><br><span class="line"> &gt; None</span><br><span class="line"></span><br><span class="line"># 要不要做视图测试</span><br><span class="line">Would you like to <span class="keyword">do</span> view based testing? [ Yes / No ]</span><br><span class="line"> &gt; Yes</span><br><span class="line"></span><br><span class="line"># 类前缀名</span><br><span class="line">What is your <span class="keyword">class</span> prefix?</span><br><span class="line"> &gt; GJ</span><br></pre></td></tr></table></figure><h3 id="pod项目安装"><a href="#pod项目安装" class="headerlink" title="pod项目安装"></a>pod项目安装</h3><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 安装CocoaPods项目</span></span><br><span class="line">pod install --no-repo-update</span><br></pre></td></tr></table></figure><ul><li>将项目添加到库的Classes文件夹中</li></ul><h3 id="编辑CocoaPods的配置文件（后缀名为podspec"><a href="#编辑CocoaPods的配置文件（后缀名为podspec" class="headerlink" title="编辑CocoaPods的配置文件（后缀名为podspec)"></a>编辑CocoaPods的配置文件（后缀名为podspec)</h3><p><img src="/./2022/04/02/custom-repo-ios/editpodspec.png" alt="编辑CocoaPods的配置文件"></p><!--  --><h3 id="pod项目更新"><a href="#pod项目更新" class="headerlink" title="pod项目更新"></a>pod项目更新</h3><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 更新CocoaPods项目</span></span><br><span class="line">pod update --no-repo-update</span><br></pre></td></tr></table></figure><h3 id="验证pod配置文件"><a href="#验证pod配置文件" class="headerlink" title="验证pod配置文件"></a>验证pod配置文件</h3><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 验证pod配置文件</span></span><br><span class="line">pod lib lint</span><br></pre></td></tr></table></figure><h3 id="发布项目"><a href="#发布项目" class="headerlink" title="发布项目"></a>发布项目</h3><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"># 添加远程地址,即上面创建码云项目的地址</span><br><span class="line">BetterdeMacBook-Pro:PrivateHelloWorld better$ git remote add origin https:<span class="comment">//gitee.com/Better_Y/PrintHelloWorld.git</span></span><br><span class="line"># 添加文件</span><br><span class="line">BetterdeMacBook-Pro:PrivateHelloWorld better$ git add .</span><br><span class="line"># 提交本地，并写描述</span><br><span class="line">BetterdeMacBook-Pro:PrivateHelloWorld better$ git commit -a -m <span class="string">&quot;第一次提交 版本为0.0.1&quot;</span></span><br><span class="line"># --allow-unrelated-histories</span><br><span class="line"><span class="meta"># git pull origin maste会失败 ,提示：fatal: refusing to merge unrelated histories</span></span><br><span class="line"># 原因是远程仓库origin上的分支master和本地分支master被Git认为是不同的仓库，所以不能直接合并，需要添加 --allow-unrelated-histories</span><br><span class="line"></span><br><span class="line">BetterdeMacBook-Pro:PrivateHelloWorld better$ git pull origin master --allow-unrelated-histories</span><br><span class="line"># 推送到码云的PrintHelloWolrd项目的master分支上</span><br><span class="line">BetterdeMacBook-Pro:PrivateHelloWorld better$ git push origin master</span><br><span class="line"># 提交版本号</span><br><span class="line">BetterdeMacBook-Pro:PrivateHelloWorld better$ git tag <span class="number">0.0</span><span class="number">.1</span></span><br><span class="line"><span class="meta"># push到远程分支</span></span><br><span class="line">BetterdeMacBook-Pro:PrivateHelloWorld better$ git push origin <span class="number">0.0</span><span class="number">.1</span></span><br></pre></td></tr></table></figure><h3 id="创建并发布Sepc管理库"><a href="#创建并发布Sepc管理库" class="headerlink" title="创建并发布Sepc管理库"></a>创建并发布Sepc管理库</h3><figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建Sepc</span></span><br><span class="line">pod repo add [repo-name] [git-url]</span><br><span class="line"><span class="comment">// 发布</span></span><br><span class="line">pod repo push [repo-name] [name.podspec]</span><br><span class="line"><span class="comment">// 删除</span></span><br><span class="line">pod repo remove [repo-name]</span><br></pre></td></tr></table></figure><h3 id="使用Cocoapods私有库"><a href="#使用Cocoapods私有库" class="headerlink" title="使用Cocoapods私有库"></a>使用Cocoapods私有库</h3><ul><li>指定其他工程的<code>Podfile</code>文件中<code>source</code>字段为私有仓库<code>repo</code>仓库地址<figure class="highlight objectivec"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pod <span class="string">&#x27;repo-name&#x27;</span>, :source=&gt;<span class="string">&#x27;cocoapods-repo-url&#x27;</span></span><br></pre></td></tr></table></figure></li></ul>]]></content>
    
    
    <summary type="html">&lt;h3 id=&quot;创建私有pod库：&quot;&gt;&lt;a href=&quot;#创建私有pod库：&quot; class=&quot;headerlink&quot; title=&quot;创建私有pod库：&quot;&gt;&lt;/a&gt;创建私有pod库：&lt;/h3&gt;&lt;p&gt;创建公有Pod库或者私有Pod库, 实际上原理是一样的, 都是基于git服务和repo协议, 不一样的是, 两者的版本索引查询方式不一样, 公有库的podspec由CocoaPods&amp;#x2F;Specs管理, 而内部私有使用的pod库需要自己建立一个仓库来管理podspec.&lt;/p&gt;
&lt;figure class=&quot;highlight objectivec&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;3&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// 创建pod库&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;&lt;span class=&quot;comment&quot;&gt;// 例如：pod lib create GJNotifyView&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;pod lib create [repo-name]&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/figure&gt;</summary>
    
    
    
    <category term="iOS工具" scheme="https://shaogithub.github.io/categories/iOS%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="iOS" scheme="https://shaogithub.github.io/tags/iOS/"/>
    
    <category term="cocoapods" scheme="https://shaogithub.github.io/tags/cocoapods/"/>
    
  </entry>
  
  <entry>
    <title>JKCategories</title>
    <link href="https://shaogithub.github.io/2022/03/24/jk-categories/"/>
    <id>https://shaogithub.github.io/2022/03/24/jk-categories/</id>
    <published>2022-03-24T14:08:01.000Z</published>
    <updated>2022-03-24T14:26:56.537Z</updated>
    
    <content type="html"><![CDATA[<h4 id="JKCategories-iOS-Categories"><a href="#JKCategories-iOS-Categories" class="headerlink" title="JKCategories(iOS-Categories)"></a>JKCategories(iOS-Categories)</h4><p>JKCategories(iOS-Categories)，一个有用的Objective-C类别的集合，扩展了iOS框架，如Foundation、UIKit、CoreData、QuartzCore、CoreLocation、MapKit等。</p><span id="more"></span><h4 id="Requirements"><a href="#Requirements" class="headerlink" title="Requirements"></a>Requirements</h4><p>此库需要<code>iOS 7.0+</code>和<code>Xcode 8.0+</code>。</p><h4 id="Installation"><a href="#Installation" class="headerlink" title="Installation"></a>Installation</h4><h5 id="安装椰荚"><a href="#安装椰荚" class="headerlink" title="安装椰荚"></a>安装椰荚</h5><p>使用“所有类别”时：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">platform :ios</span><br><span class="line">pod &#x27;JKCategories&#x27;</span><br></pre></td></tr></table></figure><p>当您要使用某种类型的框架库时，例如<code>Foundation</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">platform :ios</span><br><span class="line">pod &#x27;JKCategories/Foundation&#x27;</span><br></pre></td></tr></table></figure><p>当您要使用更详细的类类型库时，在某个单类型框架库中，例如<code>Foundation&#39;s NSDictionary</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">platform :ios</span><br><span class="line">pod &#x27;JKCategories/Foundation/NSDictionary&#x27;</span><br></pre></td></tr></table></figure><p>您将找到带有<code>pod search JKCategories</code>或<code>Podfile</code>或项目文件夹层次结构中的所有子库</p><h4 id="Manually"><a href="#Manually" class="headerlink" title="Manually"></a>Manually</h4><p>将JKCategories或某些特定的类文件复制到项目中</p><h4 id="Usage"><a href="#Usage" class="headerlink" title="Usage"></a>Usage</h4><p>将头文件导入任何希望使用诸如</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">#import &quot;NSArray+JKSafeAccess.h&quot; or &quot;&lt;JKCategories/NSArray+JKSafeAccess.h&gt;&quot;</span><br></pre></td></tr></table></figure><p>不建议将JKCategories的所有头文件导入pch或baseclass</p><p>onekey导入所有类别的框架</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">&quot;JKUIKit.h&quot; or &quot;&lt;JKCategories/JKUIKit.h&gt;&quot;,</span><br><span class="line">&quot;JKFoundation.h&quot; or &quot;&lt;JKCategories/JKFoundation.h&gt;&quot;,</span><br><span class="line">&quot;JKCoreData.h&quot; or &quot;&lt;JKCategories/JKCoreData.h&gt;&quot;,</span><br><span class="line">&quot;JKCoreLocation.h&quot; or &quot;&lt;JKCategories/JKCoreLocation.h&gt;&quot;,</span><br><span class="line">&quot;JKMapKit.h&quot;  or &quot;&lt;JKCategories/JKMapKit.h&gt;&quot;,</span><br><span class="line">&quot;JKQuartzCore.h&quot;  or &quot;&lt;JKCategories/JKQuartzCore.h&gt;&quot;</span><br></pre></td></tr></table></figure><p>onekey导入所有框架的所有类别</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&quot;JKCategories.h&quot; or &lt;JKCategories/JKCategories.h&gt;</span><br></pre></td></tr></table></figure><h4 id="Content"><a href="#Content" class="headerlink" title="Content"></a>Content</h4><h5 id="Foundation"><a href="#Foundation" class="headerlink" title="Foundation"></a>Foundation</h5><p>NSArray<br>NSBundle<br>NSData<br>NSDate<br>NSDateFormatter<br>NSNotificationCenter<br>NSDictionary<br>NSException<br>NSFileManager<br>NSIndexPath<br>NSNumber<br>NSObject<br>NSSet<br>NSString<br>NSTimer<br>NSURL<br>NSUserDefaults<br>NSHTTPCookieStorage<br>NSFileHandle<br>NSRunLoop<br>NSURLRequest<br>NSOperation<br>NSInvocation<br>NSURLConnection<br>NSURLSession</p><h5 id="UIKit"><a href="#UIKit" class="headerlink" title="UIKit"></a>UIKit</h5><p>UIAlertView<br>UIApplication<br>UIBarButtonItem<br>UIBezierPath<br>UIButton<br>UIColor<br>UIFont<br>UIControl<br>UIDevice<br>UIImage<br>UIImageView<br>UILable<br>UINavigationBar<br>UINavigationController<br>UINavigationItem<br>UIResponder<br>UIScreen<br>UIScrollView<br>UISearchBar<br>UISplitViewController<br>UITableView<br>UITableViewCell<br>UITextField<br>UITextView<br>UIView<br>UIViewController<br>UIWebView<br>UIWindow<br>UIPopoverController<br>UICollectionView</p><h5 id="QuartzCore"><a href="#QuartzCore" class="headerlink" title="QuartzCore"></a>QuartzCore</h5><p>CALayer<br>CAMediaTimingFunction<br>CAAnimation<br>CAShapeLayer<br>CATransaction</p><h5 id="CoreData"><a href="#CoreData" class="headerlink" title="CoreData"></a>CoreData</h5><p>NSManagedObjectContext<br>NSFetchRequest<br>NSManagedObject<br>NSPersistentStoreCoordinator</p><h5 id="CoreLocation"><a href="#CoreLocation" class="headerlink" title="CoreLocation"></a>CoreLocation</h5><p>CLLocationManager<br>CLLocation</p><h5 id="MapKit"><a href="#MapKit" class="headerlink" title="MapKit"></a>MapKit</h5><p>MKMapView</p>]]></content>
    
    
    <summary type="html">&lt;h4 id=&quot;JKCategories-iOS-Categories&quot;&gt;&lt;a href=&quot;#JKCategories-iOS-Categories&quot; class=&quot;headerlink&quot; title=&quot;JKCategories(iOS-Categories)&quot;&gt;&lt;/a&gt;JKCategories(iOS-Categories)&lt;/h4&gt;&lt;p&gt;JKCategories(iOS-Categories)，一个有用的Objective-C类别的集合，扩展了iOS框架，如Foundation、UIKit、CoreData、QuartzCore、CoreLocation、MapKit等。&lt;/p&gt;</summary>
    
    
    
    <category term="iOS工具" scheme="https://shaogithub.github.io/categories/iOS%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="iOS" scheme="https://shaogithub.github.io/tags/iOS/"/>
    
    <category term="工具类" scheme="https://shaogithub.github.io/tags/%E5%B7%A5%E5%85%B7%E7%B1%BB/"/>
    
  </entry>
  
  <entry>
    <title>Hello World</title>
    <link href="https://shaogithub.github.io/2022/03/21/hello-world/"/>
    <id>https://shaogithub.github.io/2022/03/21/hello-world/</id>
    <published>2022-03-21T15:47:38.502Z</published>
    <updated>2022-03-24T13:53:08.553Z</updated>
    
    <content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><span id="more"></span><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;Welcome to &lt;a href=&quot;https://hexo.io/&quot;&gt;Hexo&lt;/a&gt;! This is your very first post. Check &lt;a href=&quot;https://hexo.io/docs/&quot;&gt;documentation&lt;/a&gt; for more info. If you get any problems when using Hexo, you can find the answer in &lt;a href=&quot;https://hexo.io/docs/troubleshooting.html&quot;&gt;troubleshooting&lt;/a&gt; or you can ask me on &lt;a href=&quot;https://github.com/hexojs/hexo/issues&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</summary>
    
    
    
    
  </entry>
  
</feed>
