<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Nauyam</title>
  
  <subtitle>👨‍💻💻📱🛠</subtitle>
  <link href="https://rmb.ma/atom.xml" rel="self"/>
  
  <link href="https://rmb.ma/"/>
  <updated>2021-09-16T05:41:17.486Z</updated>
  <id>https://rmb.ma/</id>
  
  <author>
    <name>Ma</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>图片显示尺寸计算方法</title>
    <link href="https://rmb.ma/posts/%E5%88%86%E7%B1%BB/2021-09-14-%E5%9B%BE%E7%89%87%E6%98%BE%E7%A4%BA%E5%B0%BA%E5%AF%B8%E8%AE%A1%E7%AE%97%E6%96%B9%E6%B3%95.html"/>
    <id>https://rmb.ma/posts/%E5%88%86%E7%B1%BB/2021-09-14-%E5%9B%BE%E7%89%87%E6%98%BE%E7%A4%BA%E5%B0%BA%E5%AF%B8%E8%AE%A1%E7%AE%97%E6%96%B9%E6%B3%95.html</id>
    <published>2021-09-14T15:47:35.000Z</published>
    <updated>2021-09-16T05:41:17.486Z</updated>
    
    <content type="html"><![CDATA[<h1 id="图片显示尺寸计算方法"><a href="#图片显示尺寸计算方法" class="headerlink" title="图片显示尺寸计算方法"></a>图片显示尺寸计算方法</h1><p>背景：拿到一张原始图片的尺寸，在一个最大最小范围内，综合原始图片比例，计算需要显示的大小。直接贴代码</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><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><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line">imageResize(double width, double height) &#123;</span><br><span class="line">    // 最大/最小范围</span><br><span class="line">    double maxW = 140;</span><br><span class="line">    double maxH = 140;</span><br><span class="line">    double minW = 79;</span><br><span class="line">    double minH = 79;</span><br><span class="line">    </span><br><span class="line">    double resizeW = 0;</span><br><span class="line">    double resizeH = 0;</span><br><span class="line">    </span><br><span class="line">    double minScale = minW/maxW;</span><br><span class="line">    double maxScale = maxW/minW;</span><br><span class="line">    double scale = width/height;</span><br><span class="line"></span><br><span class="line">    if (scale &lt; minScale) &#123;</span><br><span class="line">        // 实际比例小于最小比例</span><br><span class="line">        // 按最小比例设置宽高</span><br><span class="line">        resizeW = minW;</span><br><span class="line">        resizeH = maxH;</span><br><span class="line">    &#125; else if(scale &lt;= 1) &#123;</span><br><span class="line">        // 实际比例小于1，分三种情况</span><br><span class="line">        // 宽 &lt; 高</span><br><span class="line">        // 用短边比较最大最小值。短了补短边，长边按比例；长了削长边，短边按比例</span><br><span class="line">        if (width &lt; minW) &#123;</span><br><span class="line">            // 宽度小于最小宽，补齐宽度</span><br><span class="line">            // 高度按比例</span><br><span class="line">            resizeW = minW;</span><br><span class="line">            resizeH = resizeW/scale;</span><br><span class="line">        &#125; else if (width &lt;= maxW &amp;&amp; height &lt;= maxH) &#123;</span><br><span class="line">            // 宽度小于等于最大宽，取原值</span><br><span class="line">            resizeW = width;</span><br><span class="line">            resizeH = height;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            // 宽度大于最大宽，高度必然大于最大高，高度取最大高</span><br><span class="line">            // 宽度按比例计算</span><br><span class="line">            resizeH = maxH;</span><br><span class="line">            resizeW = resizeH*scale;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else if(scale &gt; 1 &amp;&amp; scale &lt; maxScale) &#123;</span><br><span class="line">        // 比例介于 1 与 最大比例之间</span><br><span class="line">        // 宽 &gt; 高</span><br><span class="line">        // 用短边比较最大最小值。短了补短边，长边按比例；长了削长边，短边按比例</span><br><span class="line"></span><br><span class="line">        if (height &lt; minH) &#123;</span><br><span class="line">            // 高度小于最小高度，补齐到最小高度</span><br><span class="line">            // 宽度按比例</span><br><span class="line">            resizeH = minH;</span><br><span class="line">            resizeW = resizeH*scale;</span><br><span class="line"></span><br><span class="line">        &#125; else if (height &lt;= maxH &amp;&amp; width &lt;= maxW) &#123;</span><br><span class="line">            // 高度小于最小高度，取原值</span><br><span class="line">            // 两个值都介于最大最小之间，取原值</span><br><span class="line">            resizeW = width;</span><br><span class="line">            resizeH = height;</span><br><span class="line">            </span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            // 高度大于最大高，宽度也大于最大宽，宽度设为最大宽</span><br><span class="line">            // 高度按比例</span><br><span class="line">            resizeW = maxW;</span><br><span class="line">            resizeH = resizeW/scale;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        // 均大于最大值，取最大值</span><br><span class="line">        resizeH = minH;</span><br><span class="line">        resizeW = maxW;</span><br><span class="line">    &#125;</span><br><span class="line">    return [resizeW,resizeH];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">描述</summary>
    
    
    
    <category term="分类" scheme="https://rmb.ma/categories/%E5%88%86%E7%B1%BB/"/>
    
    
    <category term="标签" scheme="https://rmb.ma/tags/%E6%A0%87%E7%AD%BE/"/>
    
  </entry>
  
  <entry>
    <title>Certbot 设置 Let&#39;s Encrypt 日志</title>
    <link href="https://rmb.ma/posts/%E6%9C%8D%E5%8A%A1%E5%99%A8/2020-08-16-Certbot%20%E8%AE%BE%E7%BD%AE%20Let&#39;s%20Encrypt%20%E6%97%A5%E5%BF%97.html"/>
    <id>https://rmb.ma/posts/%E6%9C%8D%E5%8A%A1%E5%99%A8/2020-08-16-Certbot%20%E8%AE%BE%E7%BD%AE%20Let&#39;s%20Encrypt%20%E6%97%A5%E5%BF%97.html</id>
    <published>2020-08-16T06:41:39.000Z</published>
    <updated>2020-08-15T16:50:45.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Certbot-设置-Let’s-Encrypt-日志"><a href="#Certbot-设置-Let’s-Encrypt-日志" class="headerlink" title="Certbot 设置 Let’s Encrypt 日志"></a>Certbot 设置 Let’s Encrypt 日志</h1><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>ssl 证书到期，需要更新，按常规方式 <code>certbot renew</code>  <code>./certbot-auto renew</code>失败。<br>出现过问题：Python 环境问题，certbot 版本问题，plugin 版本问题等等。</p><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">python virtualenv 问题</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">An unexpected error occurred:</span><br><span class="line">pkg_resources.VersionConflict: (certbot 0.31.0 (/usr/lib/python3/dist-packages), Requirement.parse(‘certbot&gt;=0.34.0’))</span><br><span class="line">Please see the logfile ‘/tmp/tmpbyuigqhc’ for more details.</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">Saving debug log to /var/log/letsencrypt/letsencrypt.log</span><br><span class="line">Could not choose appropriate plugin: The requested nginx plugin does not appear to be installed</span><br><span class="line">The requested nginx plugin does not appear to be installed</span><br></pre></td></tr></table></figure><h2 id="排查过程"><a href="#排查过程" class="headerlink" title="排查过程"></a>排查过程</h2><ol><li>重新部署Python 环境，安装缺失插件（无效）</li><li>查看 <code>which certbot</code> 安装位置，发现是用 pip3 安装的，然后 <code>pip3</code> 更新软件包（无效）</li><li>certbot 源码编译安装，替换 certbot 文件（无效，出现 acme 版本问题，plugin 问题）</li><li>删除 pip3 安装的 certbot 以及关联文件，重新安装（无效）</li><li>再次删除 pip3 安装的 certbot 文件，重新 <code>which certbot</code> 发现 apt 也安装过一份</li><li>删除 apt 安装的 certbot，重新 <code>which certbot</code> 发现 snap 也安装过（😓）</li><li>删除 snap 安装的 certbot，重新 <code>which certbot</code> 无结果，清除完成</li><li>官方方式 snap 安装，certbot 执行成功，然后使用 <code>certbot-dns-cloudflare</code> 插件（提示未安装）</li><li>apt 安装 <code>certbot-dns-cloudflare</code>，之后 certbot 执行再次出问题，日志显示 certbot 版本回退到 0.4 版本，certbot 执行位置再次恢复至 Python</li><li>再次 pip3 ，apt , snap 全部清除 certbot 及其关联文件。</li><li>再次 snap 安装 certbot，测试成功之后，使用 pip3 安装 <code>certbot-dns-cloudflare</code> 插件，成功！</li></ol><hr><blockquote><p>注意： 有些教程中使用 apt 安装插件，有如下命令，实际过程中会出现<br><code>E: The repository &#39;http://ppa.launchpad.net/certbot/certbot/ubuntu focal Release&#39; does not have a Release file.</code> 类似错误，查阅资料有网友说这种方式已经不再推荐。故使用 snap 安装 certbot 及 pip 安装相关插件。</p></blockquote><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></pre></td><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get install software-properties-common</span><br><span class="line">sudo add-apt-repository universe</span><br><span class="line">sudo add-apt-repository ppa:certbot/certbot</span><br><span class="line">sudo apt-get update</span><br></pre></td></tr></table></figure><h2 id="相关执行命令"><a href="#相关执行命令" class="headerlink" title="相关执行命令"></a>相关执行命令</h2><ul><li><p>pip3 清除软件包<br><code>pip3 uninstall certbot</code></p></li><li><p>apt 清除软件包<br><code>sudo apt-get remove certbot </code></p></li><li><p>snap 清除软件包<br> <code>sudo snap remove certbot</code></p></li><li><p><code>certbot</code>安装<br><code>sudo snap install --classic certbot</code></p></li><li><p><code>certbot-dns-cloudflare</code> 插件安装<br><code>pip3 install certbot-dns-cloudflare</code></p></li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ol><li>清除所有 certbot 安装包，包括 pip apt snap</li><li>使用 snap 安装  <code>sudo snap install --classic certbot </code></li><li>使用 <code>pip3 install certbot-dns-cloudflare</code> 安装插件</li></ol><h3 id="附：证书申请命令"><a href="#附：证书申请命令" class="headerlink" title="附：证书申请命令"></a>附：证书申请命令</h3><p>1.certbot</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">certbot certonly --preferred-challenges dns --manual  -d example.com -d *.example.com --server https://acme-v02.api.letsencrypt.org/directory</span><br></pre></td></tr></table></figure><p>2.certbot-auto </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">./certbot-auto certonly --email user@mail.com -d example.com -d *.example.com  --manual --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory  </span><br></pre></td></tr></table></figure><p>3.自动化</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><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">sudo certbot certonly -d example.com -d *.example.com  \</span><br><span class="line">    --agree-tos \</span><br><span class="line">    --email user@mail.com \</span><br><span class="line">    --server https://acme-v02.api.letsencrypt.org/directory \</span><br><span class="line">    --dns-cloudflare \</span><br><span class="line">    --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \</span><br><span class="line">    --dns-cloudflare-propagation-seconds 30</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">Certbot 踩坑</summary>
    
    
    
    <category term="服务器" scheme="https://rmb.ma/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    
    <category term="踩坑" scheme="https://rmb.ma/tags/%E8%B8%A9%E5%9D%91/"/>
    
  </entry>
  
  <entry>
    <title>runtime知识点</title>
    <link href="https://rmb.ma/posts/iOS/2019-05-19-runtime%E7%9F%A5%E8%AF%86%E7%82%B9.html"/>
    <id>https://rmb.ma/posts/iOS/2019-05-19-runtime%E7%9F%A5%E8%AF%86%E7%82%B9.html</id>
    <published>2019-05-19T06:41:39.000Z</published>
    <updated>2020-08-14T03:16:04.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="isa"><a href="#isa" class="headerlink" title="isa"></a>isa</h2><p>arm64 架构之前，isa 是一个普通的指针，存储 class、metal-class 对象的内存地址。<br>arm64 架构开始，对 isa 进行了优化，变成了 <code>union </code>共用体结构，使用位域来存储更多信息。</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><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></pre></td><td class="code"><pre><span class="line">union isa_t &#123;</span><br><span class="line">    isa_t() &#123; &#125;</span><br><span class="line">    isa_t(uintptr_t value) : bits(value) &#123; &#125;</span><br><span class="line"></span><br><span class="line">    Class cls;</span><br><span class="line">    uintptr_t bits;</span><br><span class="line">#if defined(ISA_BITFIELD)</span><br><span class="line">    struct &#123;</span><br><span class="line">        ISA_BITFIELD;  // defined in isa.h</span><br><span class="line">    &#125;;</span><br><span class="line">#endif</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">#define ISA_BITFIELD                                                      \</span><br><span class="line">      uintptr_t nonpointer        : 1;                                       \</span><br><span class="line">      uintptr_t has_assoc         : 1;                                       \</span><br><span class="line">      uintptr_t has_cxx_dtor      : 1;                                       \</span><br><span class="line">      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \</span><br><span class="line">      uintptr_t magic             : 6;                                       \</span><br><span class="line">      uintptr_t weakly_referenced : 1;                                       \</span><br><span class="line">      uintptr_t deallocating      : 1;                                       \</span><br><span class="line">      uintptr_t has_sidetable_rc  : 1;                                       \</span><br><span class="line">      uintptr_t extra_rc          : 19</span><br></pre></td></tr></table></figure><p>关于其中位域存储的信息的一些详解</p><ul><li><p>nonpointer</p><ul><li>0 代表普通的指针，存储着 class meta-class 对象的内存地址</li><li>1 代表优化过，使用位域存储更多信息</li></ul></li><li><p>has_assoc<br>  是否设置过关联对象，如果没有释放会更快</p></li><li><p>has_cxx_dtor<br>  是否有 C++ 的析构函数，如果没有释放会更快</p></li><li><p>shiftcls<br>  存储着 class meta-class 对象的内存地址信息</p></li><li><p>magic<br>  用于在调试时判断对象是否未完成初始化</p></li><li><p>weakly_referenced<br>  是否被弱引用指向过，如果没有释放会更快</p></li><li><p>deallocating<br>  对象是否正在释放</p></li><li><p>has_sidetable_rc</p><ul><li>引用计数器是否过大无法存储在 isa 中</li><li>如果为 1，引用计数器会存储在一个叫 SideTable 的类属性中</li></ul></li><li><p>extra_rc<br>  里面存储的值是引用计数器减 1</p></li></ul><h2 id="Class"><a href="#Class" class="headerlink" title="Class"></a>Class</h2>]]></content>
    
    
    <summary type="html">关于 runtime 的一些杂碎</summary>
    
    
    
    <category term="iOS" scheme="https://rmb.ma/categories/iOS/"/>
    
    
    <category term="iOS" scheme="https://rmb.ma/tags/iOS/"/>
    
  </entry>
  
  <entry>
    <title>Block 知识点</title>
    <link href="https://rmb.ma/posts/iOS/2019-01-13-block%20%E7%9F%A5%E8%AF%86%E7%82%B9.html"/>
    <id>https://rmb.ma/posts/iOS/2019-01-13-block%20%E7%9F%A5%E8%AF%86%E7%82%B9.html</id>
    <published>2019-01-13T11:02:23.000Z</published>
    <updated>2020-05-19T06:42:41.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="关于-Block-的一些知识点"><a href="#关于-Block-的一些知识点" class="headerlink" title="关于 Block 的一些知识点"></a>关于 Block 的一些知识点</h1><h2 id="Block-实际结构"><a href="#Block-实际结构" class="headerlink" title="Block 实际结构"></a>Block 实际结构</h2><p>先看一段示例</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">int age = 10;</span><br><span class="line">void (^block)(int) = ^(int a)&#123;</span><br><span class="line">    NSLog(@&quot;%d&quot;,age);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">block(20);</span><br></pre></td></tr></table></figure><p>将该段代码，反编译为 C++ 看看内部实现</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">xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m</span><br></pre></td></tr></table></figure><p>将生成的代码关键部分简化一下方便阅读</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></pre></td><td class="code"><pre><span class="line">int age = 10;</span><br><span class="line">void (*block)(int) = &amp;__main_block_impl_0(__main_block_func_0, &amp;__main_block_desc_0_DATA, age);</span><br><span class="line"></span><br><span class="line">block-&gt;FuncPtr(block, 20);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>实际生成一个<code>__main_block_impl_0</code>的结构体<br>名称<code>__x_block_impl_y</code>，x 为文件名，y 为 block 的编号（0、1、2…）</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><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></pre></td><td class="code"><pre><span class="line">struct __main_block_impl_0 &#123;</span><br><span class="line">  struct __block_impl impl;</span><br><span class="line">  struct __main_block_desc_0* Desc;</span><br><span class="line">  int age; // 所捕获的变量，都会放在这，这里属于值传递</span><br><span class="line">  // 结构体构造函数</span><br><span class="line">  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) &#123;</span><br><span class="line">    impl.isa = &amp;_NSConcreteStackBlock; // 栈类型</span><br><span class="line">    impl.Flags = flags;</span><br><span class="line">    impl.FuncPtr = fp; // 函数具体的指针</span><br><span class="line">    Desc = desc;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">struct __block_impl &#123;</span><br><span class="line">  void *isa;</span><br><span class="line">  int Flags;</span><br><span class="line">  int Reserved;</span><br><span class="line">  void *FuncPtr; // 实际函数的指针，通过它调用 block</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">static struct __main_block_desc_0 &#123;</span><br><span class="line">  size_t reserved;</span><br><span class="line">  size_t Block_size; // block 的大小</span><br><span class="line">&#125; __main_block_desc_0_DATA = &#123; 0, sizeof(struct __main_block_impl_0)&#125;;</span><br><span class="line"></span><br><span class="line">// 实际上就是 block 里的代码块</span><br><span class="line">static void __main_block_func_0(struct __main_block_impl_0 *__cself, int a) &#123;</span><br><span class="line">  int age = __cself-&gt;age; // bound by copy</span><br><span class="line"></span><br><span class="line">  NSLog((NSString *)&amp;__NSConstantStringImpl__var_folders_4x_pyqkl8qx7vzgklmhywl09sd40000gn_T_main_d14565_mi_0,age);</span><br><span class="line">  </span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="关于-Block-的变量捕获"><a href="#关于-Block-的变量捕获" class="headerlink" title="关于 Block 的变量捕获"></a>关于 Block 的变量捕获</h3><p>block 实际属于跨函数调用，为了保证 block 内部能够正常访问外部的变量，block 有个变量捕获机制。</p><table>   <tr>      <td colspan="2" align="center">变量类型</td>      <td>是否捕获到 block内部</td>      <td>访问方式</td>   </tr>   <tr>      <td rowspan="2" align="center">局部变量</td>      <td>auto</td>      <td align="center">√</td>      <td>值传递</td>   </tr>   <tr>      <td>static</td>      <td align="center">√</td>      <td>指针传递</td>   </tr>   <tr>      <td colspan="2" align="center">全局变量</td>      <td align="center">×</td>      <td>直接访问</td>   </tr></table><h3 id="Block-的类型"><a href="#Block-的类型" class="headerlink" title="Block 的类型"></a>Block 的类型</h3><p>block 有三种类型，通过调用 class 方法或 isa 指针查看具体类型，最终都是继承自 NSObject </p><ul><li><code>__NSGlobalBlock__ </code>(_NSConcreteGlobalBlock)</li><li><code>__NSStackBlock__ </code>(_NSConcreteStackBlock)</li><li><code>__NSMallocBlock__</code> (_NSConcreteMallocBlock)</li></ul><p><img src="/media/15892585750806.jpg" alt="应用程序的内存分配"></p><table><thead><tr><th align="center">block 类型</th><th align="center">环境</th></tr></thead><tbody><tr><td align="center"><code> __NSGlobalBlock__</code></td><td align="center">没有访问 auto 变量</td></tr><tr><td align="center"><code>__NSStackBlock__</code></td><td align="center">访问了 auto 变量</td></tr><tr><td align="center"><code>__NSMallocBlock__</code></td><td align="center"><code>__NSStackBlock__</code>调用了 copy</td></tr></tbody></table><h3 id="Block-copy"><a href="#Block-copy" class="headerlink" title="Block copy"></a>Block copy</h3><p>每一种类型 block 调用了 copy 后的结果</p><table><thead><tr><th align="center">block 的类型</th><th align="center">copy 后的存储区域</th><th align="center">copy 效果</th></tr></thead><tbody><tr><td align="center"><code>_NSConcreteGlobalBlock</code></td><td align="center">程序的数据区域</td><td align="center">什么也不做</td></tr><tr><td align="center"><code>_NSConcreteStackBlock</code></td><td align="center">栈</td><td align="center">从栈区复制到堆</td></tr><tr><td align="center"><code>_NSConcreteMallocBlock</code></td><td align="center">堆</td><td align="center">引用计数增加</td></tr></tbody></table><p><strong>在 ARC 环境下，编译器会根据情况自动将栈上的 block 复制到堆上</strong>，如下</p><ul><li>block 作为函数返回值时</li><li>将 block 赋值给 <code>__strong</code>指针时</li><li>block 作为 Cocoa api 中方法名含有 usingBlock 的方法参数时</li><li>block 作为 GCD api 中的方法参数时</li></ul><blockquote><p>所以 MRC 下 block 作为属性时建议使用 copy 修饰符修饰；ARC 下可以用 strong，也可以延续 MRC 下的写法用 copy，都不影响，因为编译器会根据情况自动操作</p></blockquote><h3 id="对象类型的-auto-变量"><a href="#对象类型的-auto-变量" class="headerlink" title="对象类型的 auto 变量"></a>对象类型的 auto 变量</h3><ul><li><p><strong>栈空间内的 block，不会强引用外部的 auto 变量。</strong></p></li><li><p>如果 block 被 copy 到堆上</p><ol><li>会调用 block 内部的 copy 函数</li><li>copy 函数内部会调用 <code>_Block_object_assign</code>函数</li><li><code>_Block_object_assign</code>函数会根据 auto 变量的修饰符（__strong、__weak、__unsafe_unreatained）做出相应操作，形成层强引用（retain）或弱引用</li></ol></li><li><p>如果 block 从堆上移除</p><ol><li>会调用 block 内部的 dispose 函数</li><li>dispose 函数内部会调用 <code>_Block_object_dispose</code> 函数</li><li><code>_Block_object_dispose</code> 函数会自动释放引用的 auto 变量(release)</li></ol></li></ul><table><thead><tr><th align="center">函数</th><th align="center">调用时机</th></tr></thead><tbody><tr><td align="center">copy 函数</td><td align="center">栈上的 block 复制到堆时</td></tr><tr><td align="center">dispose</td><td align="center">堆上的 block 被废弃时</td></tr></tbody></table><p>看一下，block 内引用对象时，block 内部结构变化</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><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Person *obj = [[Person alloc] init];</span><br><span class="line">obj.age = 10;</span><br><span class="line"></span><br><span class="line">void (^block)(void) = ^()&#123;</span><br><span class="line">    NSLog(@&quot;%d&quot;,obj.age);</span><br><span class="line">&#125;;</span><br><span class="line">block();</span><br></pre></td></tr></table></figure><p>编译为 C++ 代码后，相比引用基本数据类型会有如下变化。</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><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">static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) &#123;_Block_object_assign((void*)&amp;dst-&gt;obj, (void*)src-&gt;obj, 3/*BLOCK_FIELD_IS_OBJECT*/);&#125;</span><br><span class="line"></span><br><span class="line">static void __main_block_dispose_0(struct __main_block_impl_0*src) &#123;_Block_object_dispose((void*)src-&gt;obj, 3/*BLOCK_FIELD_IS_OBJECT*/);&#125;</span><br><span class="line"></span><br><span class="line">static struct __main_block_desc_0 &#123;</span><br><span class="line">  size_t reserved;</span><br><span class="line">  size_t Block_size;</span><br><span class="line">  // 此结构体会多出如下两个，对内部访问的对象进行内存管理</span><br><span class="line">  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);</span><br><span class="line">  void (*dispose)(struct __main_block_impl_0*);</span><br><span class="line">&#125; __main_block_desc_0_DATA = &#123; 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="block-修饰符"><a href="#block-修饰符" class="headerlink" title="__block 修饰符"></a>__block 修饰符</h2><p><code>__block</code>用于解决 block 内部无法修改 auto 变量的问题，不能用于修改全局变量、静态变量（static）。</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></pre></td><td class="code"><pre><span class="line">__block int age = 10;</span><br><span class="line"> void (^block)(void) = ^()&#123;</span><br><span class="line">     age = 20;</span><br><span class="line">     NSLog(@&quot;%d&quot;,age);</span><br><span class="line"> &#125;;</span><br></pre></td></tr></table></figure><p>编译为 C++ 代码后，会有以下片段，<code>__block</code>变量会被包成一个 <code>__Block_byref_age_0</code>对象，所以在<code>__main_block_desc_0</code>也会存在 <code>copy</code>和<code>dispose</code>用于内存管理。</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><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">struct __Block_byref_age_0 &#123;</span><br><span class="line">  void *__isa;</span><br><span class="line">__Block_byref_age_0 *__forwarding; // 指向自己</span><br><span class="line"> int __flags;</span><br><span class="line"> int __size;</span><br><span class="line"> int age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">struct __main_block_impl_0 &#123;</span><br><span class="line">  struct __block_impl impl;</span><br><span class="line">  struct __main_block_desc_0* Desc;</span><br><span class="line">  __Block_byref_age_0 *age; // 被 __block 修饰的变量会有一个结构体指针</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><code>__main_block_func_0</code>函数内的实现</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><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">static void __main_block_func_0(struct __main_block_impl_0 *__cself) &#123;</span><br><span class="line">  // 获取存储 __block 变量结构体的指针</span><br><span class="line">  __Block_byref_age_0 *age = __cself-&gt;age; // bound by ref</span><br><span class="line">  // 通过 __Block_byref_age_0 指针获取内部的 __forwarding 指针，再获取内部的变量</span><br><span class="line">  (age-&gt;__forwarding-&gt;age) = 20;</span><br><span class="line">  NSLog((NSString *)&amp;__NSConstantStringImpl__var_folders_4x_pyqkl8qx7vzgklmhywl09sd40000gn_T_main_3fdaf9_mi_0,(age-&gt;__forwarding-&gt;age));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="block-内存管理"><a href="#block-内存管理" class="headerlink" title="__block 内存管理"></a>__block 内存管理</h3><ul><li>当 block 位于栈上时，不会对 <code>__block</code> 变量产生强引用</li><li>当 block copy 到堆上时<ol><li>会调用 block 内部的 copy 函数</li><li>copy 函数调用 <code>_Block_object_assign</code> 函数</li><li><code>_Block_object_assign</code>会对 <code>__block</code> 变量形成强引用（retain 一次）</li></ol></li></ul><p>block 复制到堆上时，会将内部引用的<code>__block</code>变量一起拷贝到堆上。<br>因为<code>__Block_byref_age_0</code>是一个对象，而<code>__main_block_impl_0</code>引用了这个对象，所以需要该对象的内存管理操作。</p><p><img src="/media/15894410933886.jpg" alt="block 复制到堆"></p><ul><li>当 block 从堆上移除时<ol><li>会调用 block 内部的 dispose 函数</li><li>dispose 函数会调用 <code>_Block_object_dispose</code>函数</li><li><code>_Block_object_dispose</code>函数会自动释放引用的 <code>__block</code>变量（release 一次）</li></ol></li></ul><p><img src="/media/15894416788496.jpg" alt="block 从堆上移除"></p><blockquote><p>ARC 下会对强引用的 block，自动复制到堆上，block 对<code>__block</code>变量会自动强引用；对普通的 auto 对象，会根据是<code>__strong</code>或是<code>__weak</code>形成强引用或者弱引用。<br> MRC 下将 block copy 到堆上，block 不会对<code>__block</code> 变量强引用。</p></blockquote><h4 id="对象类型的-auto变量、-block-变量"><a href="#对象类型的-auto变量、-block-变量" class="headerlink" title="对象类型的 auto变量、__block 变量"></a>对象类型的 auto变量、__block 变量</h4><ul><li>block 位于栈上时，对他们都不会产生强引用</li><li>block 位于堆上时，都会调用 copy 函数来处理他们<ol><li><p><code>__block</code>变量</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">_Block_object_assign((void*)&amp;dst-&gt;a, (void*)src-&gt;a, *BLOCK_FIELD_IS_BYREF*/);</span><br></pre></td></tr></table></figure></li><li><p>对象类型的 auto 变量</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">_Block_object_assign((void*)&amp;dst-&gt;p, (void*)src-&gt;p, 3/*BLOCK_FIELD_IS_OBJECT*/);</span><br></pre></td></tr></table></figure></li></ol></li><li>block 从堆上移除时，都会调用 dispose 函数来处理他们<ol><li><p><code>__block</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">_Block_object_dispose((void*)src-&gt;a, 8/*BLOCK_FIELD_IS_BYREF*/);</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>对象类型的 auto 变量</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">_Block_object_dispose((void*)src-&gt;p, 3/*BLOCK_FIELD_IS_OBJECT*/);</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol></li></ul><h2 id="循环引用问题"><a href="#循环引用问题" class="headerlink" title="循环引用问题"></a>循环引用问题</h2><p>ARC 下可以使用 <code>__weak</code> <code>__unsafe_unretained</code> 解决，也可以使用 <code>__block</code> 解决，block 内将引用的对象置为 nil，但是必须调用 block。<br>MRC 下可以使用 <code>__unsafe_unreatined</code>，<code>__block</code>解决</p>]]></content>
    
    
    <summary type="html">总结一些零碎底层知识点</summary>
    
    
    
    <category term="iOS" scheme="https://rmb.ma/categories/iOS/"/>
    
    
    <category term="iOS" scheme="https://rmb.ma/tags/iOS/"/>
    
  </entry>
  
  <entry>
    <title>iOS底层知识点总结</title>
    <link href="https://rmb.ma/posts/iOS/2018-12-13-%E5%BA%95%E5%B1%82%E7%9F%A5%E8%AF%86%E7%82%B9%E6%80%BB%E7%BB%93.html"/>
    <id>https://rmb.ma/posts/iOS/2018-12-13-%E5%BA%95%E5%B1%82%E7%9F%A5%E8%AF%86%E7%82%B9%E6%80%BB%E7%BB%93.html</id>
    <published>2018-12-13T11:02:23.000Z</published>
    <updated>2020-07-22T16:05:05.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="iOS-底层知识"><a href="#iOS-底层知识" class="headerlink" title="iOS 底层知识"></a>iOS 底层知识</h1><blockquote><p>总结一些零碎底层知识点</p></blockquote><h2 id="NSObject-对象内存占用分析"><a href="#NSObject-对象内存占用分析" class="headerlink" title="NSObject 对象内存占用分析"></a>NSObject 对象内存占用分析</h2><p><code>strut</code> 8个字节<br><code>int</code> 4 个字节<br>指针 8 个字节</p><p><code>NSObject</code> 系统分配 16 个字节，但 ivar 只占用 8 个字节，剩余 8 个字节空余。<br>结构体在内存中占用，是最大成员所占空间的倍数。<br>底层内存分配，分块分配按 16 的倍数</p><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">#import &lt;objc/runtime.h&gt;</span><br><span class="line">class_getInstanceSize([NSObject class])</span><br></pre></td></tr></table></figure><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">#import &lt;malloc/malloc.h&gt;</span><br><span class="line">malloc_size((_bridge const void *)obj);</span><br></pre></td></tr></table></figure><h3 id="OC-对象有三种"><a href="#OC-对象有三种" class="headerlink" title="OC 对象有三种"></a>OC 对象有三种</h3><ul><li><p>实例对象 instance<br><code>NSObject *obj = [[NSObject alloc] init] </code><br>存储 isa 指针、其它成员变量</p></li><li><p>类对象 class<br><code>Class *c = object_getClass(obj)</code><br><code>Class *c = [NSObject class]</code><br>存储 isa 指针，superclass，属性信息（@property），对象方法，协议（protocol），成员变量（ivar）<br>每个类在内存中有且只有一个类对象信息。</p></li><li><p>元类对象 meta-class<br><code>Class *meta_class = object_getClass(c)</code><br><code>Class *meta_class = objec_getClass([NSObject class])</code><br>存储 isa 指针，superclass，类方法列表<br>每个元类对象在内存只有一个。</p></li></ul><h4 id="isa-与-superclass-指向"><a href="#isa-与-superclass-指向" class="headerlink" title="isa 与 superclass 指向"></a>isa 与 superclass 指向</h4><p><img src="/media/%E5%9B%BE%E7%89%871.png" alt="isa 和 superclass"></p><hr><h2 id="KVO-实现"><a href="#KVO-实现" class="headerlink" title="KVO 实现"></a>KVO 实现</h2><ul><li>利用 runtime 动态生成监听对象的派生类（NSKVONotifying_XXX），一个全新子类，使 instance 的 isa 指向该子类</li><li>当修改 instance 对象属性时，会调用该子类重写的属性的 set 方法</li><li>set 方法会调用 <code>Foundation</code> 的 <code>_NSSetXXXValueAndNotify</code>方法</li><li><input disabled="" type="checkbox"> <code> willChangeValueForKey:</code></li><li><input disabled="" type="checkbox"> 父类原来的<code>set</code>方法</li><li><input disabled="" type="checkbox"> <code>didChangeValueForKey:</code> 内部触发监听器的监听方法<code>observeValueForKeyPath:ofObject:change:content:</code></li></ul><blockquote><p>手动调用 <code>willChangeValueForKey:</code> 和 <code>didChangeValueForKey:</code> 可以手动触发 KVO</p></blockquote><h4 id="NSKVONotifying-XXX-内部结构"><a href="#NSKVONotifying-XXX-内部结构" class="headerlink" title="NSKVONotifying_XXX 内部结构"></a>NSKVONotifying_XXX 内部结构</h4><ul><li><code>isa</code> 指向派生类自己的 metaClass </li><li><code>superClass</code> 指向原来的类</li><li><code>- (void)setXXX:</code> 重写的方法，内部调用<code>_NSSetXXXValueAndNotify</code></li><li><code>- (Class)class</code> 重写的方法，返回原来的类，目的为了隐藏派生类，隐藏 KVO 内部实现</li><li><code>- (void)dealloc</code> </li><li><code>_isKVOA</code></li></ul><hr><h2 id="KVC"><a href="#KVC" class="headerlink" title="KVC"></a>KVC</h2><blockquote><p>调用<code>setValue: forKey:</code> <code>setValue: forKeyPath:</code> 可以触发 KVO </p></blockquote><h3 id="setValue-forKey-实现原理"><a href="#setValue-forKey-实现原理" class="headerlink" title="setValue: forKey: 实现原理"></a><code>setValue: forKey:</code> 实现原理</h3><p><img src="/media/15821884262918.jpg" alt="setValue: forKey:"></p><h3 id="valueForKey-实现原理"><a href="#valueForKey-实现原理" class="headerlink" title="valueForKey:实现原理"></a><code>valueForKey:</code>实现原理</h3><p><img src="/media/15821889458101.jpg" alt="valueForKey:"></p><h2 id="load-方法"><a href="#load-方法" class="headerlink" title="load 方法"></a>load 方法</h2><p>在 runtime 加载类、分类时调用，只调用一次<br><em>根据方法的地址，直接调用</em></p><ol><li><p>首先调用所有类的 load 方法<br> 按编译顺序调用（先编译，先调用）<br> 调用子类的 load 方法之前会先调用父类的 load 方法</p></li><li><p>再调用分类的 load 方法<br> 按编译顺序调用（先编译，先调用）</p></li></ol><p><img src="/media/15866987998220.jpg" alt="分类加载方法"></p><p><img src="/media/15866989575530.jpg" alt="prepare_load_methods"></p><h2 id="initialize-方法"><a href="#initialize-方法" class="headerlink" title="initialize 方法"></a>initialize 方法</h2><p>在第一次接收到消息时调用<br>使用<code>objc_msgsend</code>调用<br>没有实现就不会调用</p><ol><li>先调用父类，再调用自己</li><li>如果分类实现了<code>initialize</code>方法，会覆盖掉父类的实现（因为消息发送机制，分类-&gt;子类-&gt;父类）</li><li>子类没有实现，会带调用父类的，可能会有多次调用，但只会初始化一次（消息发送机制）</li></ol><h2 id="关联对象"><a href="#关联对象" class="headerlink" title="关联对象"></a>关联对象</h2><p>category 的底层结构</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><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">struct category_t &#123;</span><br><span class="line">    const char *name;</span><br><span class="line">    classref_t cls;</span><br><span class="line">    struct method_list_t *instanceMethods;</span><br><span class="line">    struct method_list_t *classMethods;</span><br><span class="line">    struct protocol_list_t *protocols;</span><br><span class="line">    struct property_list_t *instanceProperties;</span><br><span class="line">    // Fields below this point are not always present on disk.</span><br><span class="line">    struct property_list_t *_classProperties;</span><br><span class="line"></span><br><span class="line">    method_list_t *methodsForMeta(bool isMeta) &#123;</span><br><span class="line">        if (isMeta) return classMethods;</span><br><span class="line">        else return instanceMethods;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);</span><br><span class="line">    </span><br><span class="line">    protocol_list_t *protocolsForMeta(bool isMeta) &#123;</span><br><span class="line">        if (isMeta) return nullptr;</span><br><span class="line">        else return protocols;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>由结构可知，分类无法添加成员变量，但是可以通过关联对象间接实现。</p><ul><li>添加关联对象</li></ul><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">void objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,id _Nullable value, objc_AssociationPolicy policy)</span><br></pre></td></tr></table></figure><ul><li>获取关联对象</li></ul><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">id _Nullable objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)</span><br></pre></td></tr></table></figure><ul><li>移除所有关联对象</li></ul><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">void objc_removeAssociatedObjects(id _Nonnull object)</span><br></pre></td></tr></table></figure><h3 id="关联对象的原理"><a href="#关联对象的原理" class="headerlink" title="关联对象的原理"></a>关联对象的原理</h3><p>四个核心对象</p><ul><li><code>AssociationsManager</code></li><li><code>AssociationsHashMap</code></li><li><code>ObjectAssociationMap</code></li><li><code>ObjcAssociation</code></li></ul><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><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></pre></td><td class="code"><pre><span class="line">class AssociationsManager &#123;</span><br><span class="line">    using Storage = ExplicitInitDenseMap&lt;DisguisedPtr&lt;objc_object&gt;, ObjectAssociationMap&gt;;</span><br><span class="line">    static Storage _mapStorage;</span><br><span class="line"></span><br><span class="line">public:</span><br><span class="line">    AssociationsManager()   &#123; AssociationsManagerLock.lock(); &#125;</span><br><span class="line">    ~AssociationsManager()  &#123; AssociationsManagerLock.unlock(); &#125;</span><br><span class="line"></span><br><span class="line">    AssociationsHashMap &amp;get() &#123;</span><br><span class="line">        return _mapStorage.get();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    static void init() &#123;</span><br><span class="line">        _mapStorage.init();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><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">typedef DenseMap&lt;DisguisedPtr&lt;objc_object&gt;, ObjectAssociationMap&gt; AssociationsHashMap;</span><br></pre></td></tr></table></figure><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">typedef DenseMap&lt;const void *, ObjcAssociation&gt; ObjectAssociationMap;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line">class ObjcAssociation &#123;</span><br><span class="line">    uintptr_t _policy;</span><br><span class="line">    id _value;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/media/15891858311005.jpg" alt="关联对象实现的四个核心类关系"></p><ol><li>关联对象不是存储在被关联对象的内存中。</li><li>关联对象存储在全局统一的<code>AssociationsManager</code>中。</li><li>设置关联对象为 nil，相当于移除<code>AssociationMap</code>中的所属项。</li><li><code>objc_removeAssociatedObjects</code> 相当于移除<code>AssociationsHashMap</code>的所属项目。</li></ol><h3 id="Runloop"><a href="#Runloop" class="headerlink" title="Runloop"></a>Runloop</h3>]]></content>
    
    
    <summary type="html">总结一些零碎底层知识点</summary>
    
    
    
    <category term="iOS" scheme="https://rmb.ma/categories/iOS/"/>
    
    
    <category term="iOS" scheme="https://rmb.ma/tags/iOS/"/>
    
  </entry>
  
  <entry>
    <title>iOS 知识点总结</title>
    <link href="https://rmb.ma/posts/iOS/2017-08-23-iOS-%E7%9F%A5%E8%AF%86%E7%82%B9%E6%80%BB%E7%BB%93.html"/>
    <id>https://rmb.ma/posts/iOS/2017-08-23-iOS-%E7%9F%A5%E8%AF%86%E7%82%B9%E6%80%BB%E7%BB%93.html</id>
    <published>2017-08-23T14:00:34.000Z</published>
    <updated>2018-06-19T08:21:49.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="知识点总结"><a href="#知识点总结" class="headerlink" title="知识点总结"></a>知识点总结</h3><hr><h4 id="1-内存管理"><a href="#1-内存管理" class="headerlink" title="1. 内存管理"></a>1. 内存管理</h4><ol><li><a href="#1.1">autoreleasepool，一个，还是多个。</a></li><li><a href="#1.2">autoreleasepool 与线程的关系</a></li><li><a href="#1.3">assign, strong, weak, copy, retain, nonatomic, atomic </a></li><li><a href="#1.4">MRC 与 ARC 环境下重写 getter 和 setter 方法</a></li><li><a href="#1.5">weak 属性的对象是如何在对象释放之后，指向 nil 的</a></li><li><a href="#1.6"> <code>__unsafe_unretained</code>，<code>__strong</code>，<code>__weak</code>，<code>__autoreleasing</code></a></li></ol><h4 id="2-多线程"><a href="#2-多线程" class="headerlink" title="2. 多线程"></a>2. 多线程</h4><ol><li><a href="#2.1">GCD, NSThread, NSOperation 区别，对比</a></li><li><a href="#2.2">线程和进程</a></li><li><a href="#2.3">2.3 单例</a></li></ol><h4 id="3-Runloop"><a href="#3-Runloop" class="headerlink" title="3. Runloop"></a>3. Runloop</h4><ol><li><a href="#3.1">Runloop 与线程的关系</a></li></ol><h4 id="4-Runtime"><a href="#4-Runtime" class="headerlink" title="4. Runtime"></a>4. Runtime</h4><ol><li><a href="4,1">消息机制，内部的缓存机制</a></li><li><a href="4.2">黑魔法</a></li><li><a href="#4.3">ivar 和 property</a></li></ol><h4 id="5-Block"><a href="#5-Block" class="headerlink" title="5. Block"></a>5. Block</h4><ol><li><a href="#5.1">三种block，原理</a></li><li><a href="#5.2">作为成员变量时的修饰，strong，copy</a></li><li><a href="#5.3">__weak 和 __block 的区别</a></li><li><a href="#5.4">block 和函数指针的区别</a></li><li><a href="#5.5">循环引用</a></li></ol><h4 id="6-KVO"><a href="#6-KVO" class="headerlink" title="6. KVO"></a>6. KVO</h4><ol><li><a href="#6.1">KVC</a></li><li><a href="#6.2">KVO</a></li><li><a href="#6.3">KVO 系统是怎么知道监听的对象发生了变化</a></li><li><a href="#6.4">如何手动触发 KVO</a></li></ol><h4 id="7-Category-分类"><a href="#7-Category-分类" class="headerlink" title="7. Category 分类"></a>7. Category 分类</h4><ol><li><a href="#7.1">原理</a></li><li><a href="#7.2">扩展 <code>@property</code></a></li><li><a href="#7.3">加载顺序 </a></li></ol><h4 id="8-UIView"><a href="#8-UIView" class="headerlink" title="8. UIView"></a>8. UIView</h4><ol><li><a href="#8.1">UIView 与 CALayer 区别</a></li><li><a href="#8.2">层级问题</a></li><li><a href="#8.3">事件响应链</a></li><li><a href="#8.4">绘图架构</a></li><li><a href="#8.5">图文混排</a></li><li><a href="#8.6">CoreText 原理</a></li><li><a href="#8.7">动画</a></li></ol><h4 id="9-UIViewController"><a href="#9-UIViewController" class="headerlink" title="9. UIViewController"></a>9. UIViewController</h4><ol><li><a href="#9.1">生命周期</a></li></ol><h4 id="10-网络"><a href="#10-网络" class="headerlink" title="10. 网络"></a>10. 网络</h4><ol><li><a href="#10.1">TCP 协议</a></li><li><a href="#10.2">GET 与 POST</a></li><li><a href="#10.3">三次握手</a></li><li><a href="#10.4">HTTPS 原理</a></li></ol><h4 id="11-其它"><a href="#11-其它" class="headerlink" title="11. 其它"></a>11. 其它</h4><ol><li><a href="#11.1">load 加载的顺序, initialize， 执行时间。</a></li><li><a href="#11.2">main 函数执行后，系统做了什么</a></li><li><a href="#11.3">性能优化 UITableview 滑动优化</a></li><li><a href="#11.4">架构 MVC MVVM</a></li><li><a href="#11.5">设计模式类问题</a></li><li><a href="#11.6">字典的工作原理，系统如何从若干数据中快速读取 Value</a></li><li><a href="#11.7">NSNotification 和 Delegate 的区别</a></li><li><a href="#11.8">方法返回值类型中，id,instancetype,NsObject* 有什么区别</a></li><li><a href="#11.9">Git &amp; SVN 有什么不同</a></li><li><a href="#11.10">static &amp; const</a></li></ol><h4 id="12-算法相关"><a href="#12-算法相关" class="headerlink" title="12. 算法相关"></a>12. 算法相关</h4><ol><li><a href="#12.1">不用临时变量怎么实现 swap(a, b)——用加法或者异或都可以</a></li><li><a href="#12.2">二维有序数组查找数字——剑指 offer 第 3题</a></li><li><a href="#12.3">亿级日志中，查找登陆次数最多的十个用户——（不确定对不对，我的思路是）先用哈希表保存登陆次数和ID，然后用红黑树保存最大的十个数。剑指 offer 第 30题</a></li><li><a href="#12.4">简述排序算法——快排，partion函数的原理，堆排（不稳定），归并排序，基数排序。</a></li></ol><hr><h2 id="解答"><a href="#解答" class="headerlink" title="解答"></a>解答</h2><p><span id="1.1"> </span></p><h4 id="1-1-autoreleasepool，一个，还是多个。"><a href="#1-1-autoreleasepool，一个，还是多个。" class="headerlink" title="1.1 autoreleasepool，一个，还是多个。"></a>1.1 autoreleasepool，一个，还是多个。</h4><p>关键词 <strong>事件循环</strong>，autoreleasepol 调用 autorelease 时，对象的引用计数不会马上递减，而是先将对象放进自动释放池，通常会在下一次<strong>事件循环</strong>时递减。 因为自动释放池中的释放操作要等到下一次事件循环时才会执行。</p><p><span id="1.2"> </span></p><h4 id="1-2-autoreleasepool-与线程的关系"><a href="#1-2-autoreleasepool-与线程的关系" class="headerlink" title="1.2 autoreleasepool 与线程的关系"></a>1.2 autoreleasepool 与线程的关系</h4><p><span id="1.3"> </span></p><h4 id="1-3-assign-strong-weak-copy-retain-nonatomic-atomic"><a href="#1-3-assign-strong-weak-copy-retain-nonatomic-atomic" class="headerlink" title="1.3 assign, strong, weak, copy, retain, nonatomic, atomic"></a>1.3 assign, strong, weak, copy, retain, nonatomic, atomic</h4><ol><li>assign ： 针对 “纯量类型” 进行简单的赋值操作。可以用于非 OC 对象</li><li>strong ：表明了一种 “拥有关系”，为这种属性设置新值时，设置方法会先保留新值，并释放旧值，然后再把新值赋上去。</li><li>weak ：此特质表明了一种 “非拥有关系”，为这种属性设置新值时，设置方法既不保留新值，也不释放旧值。与 assign 类似，然而在属性所指的对象遭到摧毁时，属性值也会清空。必须用于 OC 对象</li><li>copy ：与 strong 类似，然而设置方法，并不保留新值，而是将其 拷贝。常用此来保护其封装性。</li><li>retain ：</li><li>atomic：原子属性，实际并不能保证线程安全</li><li>nonatomic：非原子属性</li></ol><p><span id="1.4"> </span></p><h4 id="1-4-MRC-与-ARC-环境下重写-getter-和-setter-方法"><a href="#1-4-MRC-与-ARC-环境下重写-getter-和-setter-方法" class="headerlink" title="1.4 MRC 与 ARC 环境下重写 getter 和 setter 方法"></a>1.4 MRC 与 ARC 环境下重写 getter 和 setter 方法</h4><p>MRC </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><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">- (void)setStr:(NSString *)str &#123;</span><br><span class="line">if (_str != str) &#123;</span><br><span class="line">[str retain];// [str copy];</span><br><span class="line">[_str release];</span><br><span class="line">_str = str; </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (NSString *)str &#123;</span><br><span class="line">return [[_str retain] autorelease];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>ARC </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><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">- (void)setStr:(NSString *)str &#123;</span><br><span class="line">if (_str != str) &#123;</span><br><span class="line">_str = str ; </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (NSString *)str &#123;</span><br><span class="line">return _str;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><span id="1.5"> </span></p><h4 id="1-5-weak-属性的对象是如何在对象释放之后，指向-nil-的"><a href="#1-5-weak-属性的对象是如何在对象释放之后，指向-nil-的" class="headerlink" title="1.5 weak 属性的对象是如何在对象释放之后，指向 nil 的"></a>1.5 weak 属性的对象是如何在对象释放之后，指向 nil 的</h4><p><span id="1.6"> </span></p><h4 id="1-6-strong，-wea，-unsafe-unretained，-autoreleasing"><a href="#1-6-strong，-wea，-unsafe-unretained，-autoreleasing" class="headerlink" title="1.6 __strong，__wea，__unsafe_unretained， __autoreleasing"></a>1.6 <code>__strong</code>，<code>__wea</code>，<code>__unsafe_unretained</code>， <code>__autoreleasing</code></h4><p><code>__strong</code> : 默认语义，表示保留此值<br><code>__weak</code> : 不保留此值，变量可以安全使用，系统如果把这个对象回收了，那么该变量也会自动清空（指向 nil ）<br><code>__unsafe_unretained</code> : 与 <code>__weak</code> 类似，但是该变量不会自动清空，不安全<br><code>__autoreleasing</code> : </p><hr><p><span id="2.1"> </span></p><h4 id="2-1-GCD-NSThread-NSOperation-区别，对比"><a href="#2-1-GCD-NSThread-NSOperation-区别，对比" class="headerlink" title="2.1 GCD, NSThread, NSOperation 区别，对比"></a>2.1 GCD, NSThread, NSOperation 区别，对比</h4><p><span id="2.2"> </span></p><h4 id="2-2-线程和进程"><a href="#2-2-线程和进程" class="headerlink" title="2.2 线程和进程"></a>2.2 线程和进程</h4><p><span id="2.3"> </span></p><h4 id="2-3-单例"><a href="#2-3-单例" class="headerlink" title="2.3 单例"></a>2.3 单例</h4><p>dispatch_once 与 static 的区别<br>dispatch_once 线程安全的，性能较高<br>static 使用原子锁保证线程安全，但每次获取都需要获取锁，性能较差</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><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">+ (instancetype)shareManager &#123;</span><br><span class="line">    static Dispatch *obj;</span><br><span class="line">    static dispatch_once_t onceToken;</span><br><span class="line">    dispatch_once(&amp;onceToken, ^&#123;</span><br><span class="line">        obj = [[Dispatch alloc] init];</span><br><span class="line">    &#125;);</span><br><span class="line">    return obj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">+ (instancetype)shareManager &#123;</span><br><span class="line">    static Static *obj;</span><br><span class="line">    @synchronized (self) &#123;// 加锁为了防止多个线程操作</span><br><span class="line">        if (!obj) &#123;</span><br><span class="line">            obj = [[Static alloc] init];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    return obj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><p><span id="3.1"> </span></p><h4 id="3-1-Runloop-与线程的关系"><a href="#3-1-Runloop-与线程的关系" class="headerlink" title="3.1 Runloop 与线程的关系"></a>3.1 Runloop 与线程的关系</h4><p>NSRunLoop 基于 <code>CFRunLoopRef</code> 的封装，提供了面向对象的 API，但不是线程安全的。<br>CFRunLoopRef 在 CoreFoundation 框架内，提供了纯 C 函数的 API，所有 API 都是线程安全的。</p><p>线程和 RunLoop 之间是一一对应的，其对应关系是保存在一个全局的 Dictionary 里。<br>线程刚创建时并没有 RunLoop，如果你不主动获取，那它一直都不会有。<br>RunLoop 的创建是发生在第一次获取时，RunLoop 的销毁是发生在线程结束时。<br>你只能在一个线程的内部获取其 RunLoop （主线程除外）。</p><p>一个 RunLoop 包含若干个 Mode，每个 Mode 又包含若干个 Source&#x2F;Time&#x2F;Observer。每次调用 RunLoop 的主函数时，只能指定其中的一个 Mode，这个 Mode 成为 CurrentMode。如果需要切换 Mode，只能退出 Loop，再重新指定一个 Mode 进入。</p><p><code>CFRunLoopSourceRef</code> 是事件产生的地方。Source 有两个版本？：Source0 和 Source1。</p><ul><li>Source0 只包含了一个回调（函数指针），它并不能主动触发事件。使用时需要先调用 <code>CFRunLoopSourceSignal(source)</code>，将这个 Source 标记为待处理，然后手动调用 <code>CFRunLoopWakeUp(runloop)</code> 来唤醒 RunLoop，让其处理这个事件。</li><li>Source1 包含了一个 mach_port 和一个回调（函数指针），被用于通过内核和其它线程相互发送消息。这个 Source 能主动唤醒 RunLoop 的线程。</li></ul><p><code>CFRunLoopTimerRef</code> 是基于时间的触发器。和 NSTimer 无缝桥接，可以混用。其包含一个时间长度和一个回调（函数指针）。当其加入到 RunLoop 时，RunLoop 会注册对应的时间点，当到达那个时间点，RunLoop 会被唤醒以执行那个回调。</p><p><code>CFRunLoopObserverRef</code> 是观察者，每个 Observer 都包含一个回调（函数指针）。当 RunLoop 的状态发生变化时，观察者就能通过这个回调接收到这个变化。</p><p>以上 Source&#x2F;Timer&#x2F;Observer 被称为 Mode item，<strong>一个 item 可以被同时加入到多个 mode。但同一个 item 被重复加入同一个 mode 时是不会有效果的。如果一个 mode 中一个 item 都没有，则 RunLoop 会直接退出，不进入循环</strong>。</p><p>RunLoop 启动后，系统默认注册了5个 Mode：</p><ol><li>kCFRunLoopDefaultMode：APP 的默认 mode，通常主线程是在这个 Mode 下运行的。</li><li>UITrackingRunLoopMode：界面跟踪 Mode，用于 ScrollView 追踪触摸滑动，保证界面滑动时不受其他 Mode 影响。</li><li>UIInitializationRunLoopMode：在刚启动 APP 时进入的第一个 Mode，启动完成后就不再使用。</li><li>GSEventReceiveRunLoopMode：接收系统事件的内部 Mode，通常用不到。</li><li>kCFRunLoopCommonModes：这是一个占位的 Mode，没有实际作用。</li></ol><p>相关链接：<br><a href="https://blog.ibireme.com/2015/05/18/runloop/">ibireme：深入理解RunLoop</a> , <a href="http://www.jianshu.com/p/10121d699c32">bestswifter：深入研究 Runloop 与线程保活</a> , <a href="http://yulingtianxia.com/blog/2017/09/17/Threading-Programming-Guide-2/">杨潇玉：Threading Programming Guide</a></p><hr><p><span id="4.1"> </span></p><h4 id="4-1-消息机制，内部的缓存机制"><a href="#4-1-消息机制，内部的缓存机制" class="headerlink" title="4.1 消息机制，内部的缓存机制"></a>4.1 消息机制，内部的缓存机制</h4><p><span id="4.2"> </span></p><h4 id="4-2-黑魔法"><a href="#4-2-黑魔法" class="headerlink" title="4.2 黑魔法"></a>4.2 黑魔法</h4><ul><li><a href="http://blog.leichunfeng.com/blog/2015/06/14/objective-c-method-swizzling-best-practice/">Objective-C Method Swizzling 的最佳实践</a></li></ul><p><span id="4.3"> </span></p><h4 id="4-3-ivar-和-property"><a href="#4-3-ivar-和-property" class="headerlink" title="4.3 ivar 和 property"></a>4.3 ivar 和 property</h4><p>property 本质由 <code>ivar + getter + setter </code> 构成<br>ivar 实例变量，getter + setter 存取方法</p><hr><p><span id="5.1"> </span></p><h4 id="5-1-三种block，原理"><a href="#5-1-三种block，原理" class="headerlink" title="5.1 三种block，原理"></a>5.1 三种block，原理</h4><p><span id="5.2"> </span></p><h4 id="5-2-作为成员变量时的修饰，strong，copy"><a href="#5-2-作为成员变量时的修饰，strong，copy" class="headerlink" title="5.2 作为成员变量时的修饰，strong，copy"></a>5.2 作为成员变量时的修饰，strong，copy</h4><p><span id="5.3"> </span></p><h4 id="5-3-weak-和-block-的区别"><a href="#5-3-weak-和-block-的区别" class="headerlink" title="5.3 __weak 和 __block 的区别"></a>5.3 __weak 和 __block 的区别</h4><p><span id="5.4"> </span></p><h4 id="5-4-block-和函数指针的区别"><a href="#5-4-block-和函数指针的区别" class="headerlink" title="5.4 block 和函数指针的区别"></a>5.4 block 和函数指针的区别</h4><p><span id="5.6"> </span></p><h4 id="5-6-循环引用"><a href="#5-6-循环引用" class="headerlink" title="5.6 循环引用"></a>5.6 循环引用</h4><hr><p><span id="6.1"> </span></p><h4 id="6-1-KVC"><a href="#6-1-KVC" class="headerlink" title="6.1 KVC"></a>6.1 KVC</h4><p>KVC 是一种基于 <code>NSKeyValueCoding</code> 非正式协议的机制，能让我们用一个或一串字符串标识符去访问，操作类的属性。</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">- (nullable id)valueForKey:(NSString *)key;</span><br><span class="line">- (void)setValue:(nullable id)value forKey:(NSString *)key;</span><br><span class="line"></span><br><span class="line">- (nullable id)valueForKeyPath:(NSString *)keyPath;</span><br><span class="line">- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>通过这些方法加上正确的标识符（一般与属性同名），可以直接获取或设置类的属性。甚至可以越过多个类的层级结构，直接获取目标属性。</p><p>还有对集合操作的方法，直接获取到集合属性的同时，对其求和、取平均数，取最大最小值等操作。</p><p><span id="6.2"> </span></p><h4 id="6-2-KVO"><a href="#6-2-KVO" class="headerlink" title="6.2 KVO"></a>6.2 KVO</h4><p>KVO 是 Cocoa 提供的一种基于  KVC 的 键值观察 机制，允许一个对象去监听另一个对象的某个属性，当该对象改变时系统通知监听的对象。</p><p><span id="6.3"> </span></p><h4 id="6-3-KVO-系统是怎么知道监听的对象发生了变化"><a href="#6-3-KVO-系统是怎么知道监听的对象发生了变化" class="headerlink" title="6.3 KVO 系统是怎么知道监听的对象发生了变化"></a>6.3 KVO 系统是怎么知道监听的对象发生了变化</h4><p>当某个类的对象第一次被观察时，系统就会在运行期动态地创建该类的一个派生类（类名就是在该类的前面加上 <code>NSKVONotifying_</code> 前缀），在这个派生类中重写基类中任何被观察属性的 setter 方法。</p><p>派生类在被重写的 <code>setter</code> 方法实现真正的通知机制，就如前面手动实现键值观察那样，调用 <code>willChangeValueForKey:</code> 和 <code>didChangeValueForKey:</code> 方法。这么做是基于设置属性会调用 setter 方法，而通过重写就获得了 KVO 需要的通知机制。当然前提是要通过遵循 KVO 的属性设置方式来变更属性值，如果仅是直接修改属性对应的成员变量，是无法实现 KVO 的。</p><p>同时派生类还重写了 <code>class</code> 方法以“欺骗”外部调用者它就是起初的那个类。然后系统将这个对象的 isa 指针指向这个新诞生的派生类，因此这个对象就成为该派生类的对象了，因而在该对象上对 setter 的调用就会调用重写的 setter，从而激活键值通知机制。此外，派生类还重写了 <code>dealloc</code> 方法来释放资源。</p><p>相关阅读：<a href="http://www.jianshu.com/p/cfd553f250f9">谈谈 KVO </a> ， <a href="http://yulingtianxia.com/blog/2014/05/12/objective-czhong-de-kvche-kvo/">Objective-C中的KVC和KVO</a></p><p><span id="6.4"> </span></p><h4 id="6-4-如何手动触发-KVO"><a href="#6-4-如何手动触发-KVO" class="headerlink" title="6.4 如何手动触发 KVO"></a>6.4 如何手动触发 KVO</h4><p>重写 <code>+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key</code>  来过滤通知<br>调用 <code>- (void)willChangeValueForKey:(NSString *)key</code> <code>- (void)didChangeValueForKey:(NSString *)key;</code> </p><hr><p><span id="7.1"> </span></p><h4 id="7-1-Category-原理"><a href="#7-1-Category-原理" class="headerlink" title="7.1 Category 原理"></a>7.1 Category 原理</h4><p><span id="7.2"> </span></p><h4 id="7-2-Category-扩展-property"><a href="#7-2-Category-扩展-property" class="headerlink" title="7.2 Category 扩展 @property"></a>7.2 Category 扩展 <code>@property</code></h4><p><span id="7.3"> </span></p><h4 id="7-3-Category-加载顺序"><a href="#7-3-Category-加载顺序" class="headerlink" title="7.3 Category 加载顺序"></a>7.3 Category 加载顺序</h4><hr><p><span id="8.1"> </span></p><h4 id="8-1-UIView-与-CALayer-区别"><a href="#8-1-UIView-与-CALayer-区别" class="headerlink" title="8.1 UIView 与 CALayer 区别"></a>8.1 UIView 与 CALayer 区别</h4><p><span id="8.2"> </span></p><h4 id="8-2-UIView-层级问题"><a href="#8-2-UIView-层级问题" class="headerlink" title="8.2 UIView 层级问题"></a>8.2 UIView 层级问题</h4><p><span id="8.3"> </span></p><h4 id="8-3-事件响应链"><a href="#8-3-事件响应链" class="headerlink" title="8.3 事件响应链"></a>8.3 事件响应链</h4><p><span id="8.4"> </span></p><h4 id="8-4-绘图架构"><a href="#8-4-绘图架构" class="headerlink" title="8.4 绘图架构"></a>8.4 绘图架构</h4><p><span id="8.5"> </span></p><h4 id="8-5-图文混排"><a href="#8-5-图文混排" class="headerlink" title="8.5 图文混排"></a>8.5 图文混排</h4><p><span id="8.6"> </span></p><h4 id="8-6-CoreText-原理"><a href="#8-6-CoreText-原理" class="headerlink" title="8.6 CoreText 原理"></a>8.6 CoreText 原理</h4><p><span id="8.7"> </span></p><h4 id="8-7-动画"><a href="#8-7-动画" class="headerlink" title="8.7 动画"></a>8.7 动画</h4><hr><p><span id="9.1"> </span></p><h4 id="9-1-UIViewController-生命周期"><a href="#9-1-UIViewController-生命周期" class="headerlink" title="9.1 UIViewController 生命周期"></a>9.1 UIViewController 生命周期</h4><hr><p><span id="10.1"> </span></p><h4 id="10-1-TCP-协议"><a href="#10-1-TCP-协议" class="headerlink" title="10.1 TCP 协议"></a>10.1 TCP 协议</h4><p><span id="10.2"> </span></p><h4 id="10-2-GET-与-POST"><a href="#10-2-GET-与-POST" class="headerlink" title="10.2 GET 与 POST"></a>10.2 GET 与 POST</h4><p><span id="10.3"> </span></p><h4 id="10-3-三次握手"><a href="#10-3-三次握手" class="headerlink" title="10.3 三次握手"></a>10.3 三次握手</h4><p><span id="10.4"> </span></p><h4 id="10-4-HTTPS-原理"><a href="#10-4-HTTPS-原理" class="headerlink" title="10.4 HTTPS 原理"></a>10.4 HTTPS 原理</h4><hr><p><span id="11.1"> </span></p><h4 id="11-1-load-加载的顺序-initialize，-执行时间。"><a href="#11-1-load-加载的顺序-initialize，-执行时间。" class="headerlink" title="11.1 load 加载的顺序, initialize， 执行时间。"></a>11.1 load 加载的顺序, initialize， 执行时间。</h4><p><code>load</code> 当文件被装载时调用，<code> main</code> 函数之前。自动调用，不可手动调用。<br>        加载顺序为 complie source 中的文件顺序，父类-&gt; 子类-&gt; 分类。<br>        子类没有实现 <code>load</code> 方法，就不会调用父类的。<br>        内部使用了锁，线程安全的，避免阻塞线程。<br>        常用于 <code>Method Swizzle</code> 。</p><p> <code>initialize</code>  实例化对象之前调用，只会调用一次，<code>main</code> 函数之后，自动调用。<br>        即使子类没有实现 <code>initialize</code> 方法，仍会调用父类的方法。<br>        常用于初始化全局变量或静态变量。</p><p><span id="11.2"> </span></p><h4 id="11-2-main-函数执行后，系统做了什么"><a href="#11-2-main-函数执行后，系统做了什么" class="headerlink" title="11.2 main 函数执行后，系统做了什么"></a>11.2 main 函数执行后，系统做了什么</h4><p><span id="11.3"> </span></p><h4 id="11-3-性能优化-UITableview-滑动优化"><a href="#11-3-性能优化-UITableview-滑动优化" class="headerlink" title="11.3 性能优化 UITableview 滑动优化"></a>11.3 性能优化 UITableview 滑动优化</h4><p><span id="11.4"> </span></p><h4 id="11-4-架构-MVC-MVVM"><a href="#11-4-架构-MVC-MVVM" class="headerlink" title="11.4 架构 MVC MVVM"></a>11.4 架构 MVC MVVM</h4><p><span id="11.5"> </span></p><h4 id="11-5-设计模式类问题"><a href="#11-5-设计模式类问题" class="headerlink" title="11.5 设计模式类问题"></a>11.5 设计模式类问题</h4><p><span id="11.6"> </span></p><h4 id="11-6-字典的工作原理，系统如何从若干数据中快速读取-Value"><a href="#11-6-字典的工作原理，系统如何从若干数据中快速读取-Value" class="headerlink" title="11.6 字典的工作原理，系统如何从若干数据中快速读取 Value"></a>11.6 字典的工作原理，系统如何从若干数据中快速读取 Value</h4><p><span id="11.7"> </span></p><h4 id="11-7-NSNotification-和-Delegate-的区别"><a href="#11-7-NSNotification-和-Delegate-的区别" class="headerlink" title="11.7 NSNotification 和 Delegate 的区别"></a>11.7 NSNotification 和 Delegate 的区别</h4><p><span id="11.8"></span></p><h4 id="方法返回值类型中，id-instancetype-NObject-有什么区别"><a href="#方法返回值类型中，id-instancetype-NObject-有什么区别" class="headerlink" title="方法返回值类型中，id,instancetype,NObject* 有什么区别"></a>方法返回值类型中，id,instancetype,NObject* 有什么区别</h4><p>id : 万能指针，可以指向任意对象类型，编译器不会做类型检。<br>instancetype : 作为一个拥有关联类型的方法的返回类型，这些方法的返回结果以当前所在的类为类型。<br>NSObject* : 并不是所有对象都是继承自 NSObject，如 NSProxy，所以并不能代指所有类型。</p><p><strong>问：为什么构造方法要用 instancetype 取代 id</strong></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><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></pre></td><td class="code"><pre><span class="line">// 父类，分别创建两个构造方法</span><br><span class="line">@interface Person:NSObject</span><br><span class="line">+ (id)person1;</span><br><span class="line">+ (instancetype)person2;</span><br><span class="line">@end</span><br><span class="line">@implementation Person</span><br><span class="line">+ (id)person1 &#123;</span><br><span class="line">return [[self alloc] init];</span><br><span class="line">&#125;</span><br><span class="line">+ (instancetype)person2 &#123;</span><br><span class="line">return [[self alloc] init];</span><br><span class="line">&#125;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">// 子类，创建一个实例方法</span><br><span class="line">@interface Student:Person</span><br><span class="line">- (void)hello;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">@implementation Student</span><br><span class="line">- (void)hello &#123;</span><br><span class="line">NSLog(@&quot;Hello World&quot;);</span><br><span class="line">&#125;</span><br><span class="line">@end</span><br><span class="line"></span><br><span class="line">// main 函数分别调用</span><br><span class="line">int main(int argc, const char *argv[]) </span><br><span class="line">&#123;</span><br><span class="line">@autoreleasepool</span><br><span class="line">&#123;</span><br><span class="line">[[Student person1] hello]; // 编译正常，运行正常</span><br><span class="line">[[Student person2] hello]; // 编译正常，运行正常</span><br><span class="line">[[Person person1] hello];  // 编译正常，运行crash （unrecognized selector sent to instance）</span><br><span class="line">[[Person person2] hello];  // 编译失败 （No visible @interface for &#x27;Person&#x27; declares the selector &#x27;hello&#x27;）</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>好处：id 可以指向任意类型，编译器不会做类型检测，即使我们调用了一个不属于该类的方法，仍然可以正常编译。 instancetype 可以更好的识别出类型，帮助我们在编译阶段发现问题。</p><p><span id="11.9"></span></p><h4 id="11-9-Git-amp-SVN-有什么不同"><a href="#11-9-Git-amp-SVN-有什么不同" class="headerlink" title="11.9 Git &amp; SVN 有什么不同"></a>11.9 Git &amp; SVN 有什么不同</h4><p>SVN 可以 lock 文件，SVN 有版本号，SVN 强制所有人提交代码前对齐基线，SVN 不可以离线log</p><p><span id="11.10"></span></p><h4 id="11-10-static-amp-const"><a href="#11-10-static-amp-const" class="headerlink" title="11.10 static &amp; const"></a>11.10 static &amp; const</h4><hr><p><span id="12.1"> </span></p><h4 id="12-1-不用临时变量怎么实现-swap-a-b-——用加法或者异或都可以"><a href="#12-1-不用临时变量怎么实现-swap-a-b-——用加法或者异或都可以" class="headerlink" title="12.1 不用临时变量怎么实现 swap(a, b)——用加法或者异或都可以"></a>12.1 不用临时变量怎么实现 swap(a, b)——用加法或者异或都可以</h4><p><span id="12.2"> </span></p><h4 id="12-2-二维有序数组查找数字——剑指-offer-第-3题"><a href="#12-2-二维有序数组查找数字——剑指-offer-第-3题" class="headerlink" title="12.2 二维有序数组查找数字——剑指 offer 第 3题"></a>12.2 二维有序数组查找数字——剑指 offer 第 3题</h4><p><span id="12.3"> </span></p><h4 id="12-3-亿级日志中，查找登陆次数最多的十个用户——（不确定对不对，我的思路是）先用哈希表保存登陆次数和ID，然后用红黑树保存最大的十个数。剑指-offer-第-30题"><a href="#12-3-亿级日志中，查找登陆次数最多的十个用户——（不确定对不对，我的思路是）先用哈希表保存登陆次数和ID，然后用红黑树保存最大的十个数。剑指-offer-第-30题" class="headerlink" title="12.3 亿级日志中，查找登陆次数最多的十个用户——（不确定对不对，我的思路是）先用哈希表保存登陆次数和ID，然后用红黑树保存最大的十个数。剑指 offer 第 30题"></a>12.3 亿级日志中，查找登陆次数最多的十个用户——（不确定对不对，我的思路是）先用哈希表保存登陆次数和ID，然后用红黑树保存最大的十个数。剑指 offer 第 30题</h4><p><span id="12.4"> </span></p><h4 id="12-4-简述排序算法——快排，partion函数的原理，堆排（不稳定），归并排序，基数排序。"><a href="#12-4-简述排序算法——快排，partion函数的原理，堆排（不稳定），归并排序，基数排序。" class="headerlink" title="12.4 简述排序算法——快排，partion函数的原理，堆排（不稳定），归并排序，基数排序。"></a>12.4 简述排序算法——快排，partion函数的原理，堆排（不稳定），归并排序，基数排序。</h4>]]></content>
    
    
    <summary type="html">iOS 基础知识点总结</summary>
    
    
    
    <category term="iOS" scheme="https://rmb.ma/categories/iOS/"/>
    
    
    <category term="iOS" scheme="https://rmb.ma/tags/iOS/"/>
    
  </entry>
  
  <entry>
    <title>脚本文件自动打包</title>
    <link href="https://rmb.ma/posts/iOS/2016-10-13-%E8%84%9A%E6%9C%AC%E6%96%87%E4%BB%B6%E8%87%AA%E5%8A%A8%E6%89%93%E5%8C%85.html"/>
    <id>https://rmb.ma/posts/iOS/2016-10-13-%E8%84%9A%E6%9C%AC%E6%96%87%E4%BB%B6%E8%87%AA%E5%8A%A8%E6%89%93%E5%8C%85.html</id>
    <published>2016-10-13T08:40:16.000Z</published>
    <updated>2018-06-19T08:21:49.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="自动打包"><a href="#自动打包" class="headerlink" title="自动打包"></a>自动打包</h1><h2 id="安装常用工具"><a href="#安装常用工具" class="headerlink" title="安装常用工具"></a>安装常用工具</h2><p>1、安装 gym </p><p><code>sudo gem install gym --verbose </code></p><p>2、安装 fastlane</p><p>· <a href="https://github.com/fastlane/fastlane">https://github.com/fastlane/fastlane</a></p><p><code>sudo gem install fastlane --verbose </code></p><p>3、安装 xctool</p><p>· <a href="https://github.com/facebook/xctool">https://github.com/facebook/xctool</a><br>· xctool是官方xcodebuild的一个增强实现，输出的内容比xcodebuild直观可读得多</p><p><code>brew install xctool  </code></p><p>4、安装fir-cli</p><p>· fir的命令行工具</p><p><code>sudo gem install fir-cli --verbose </code></p><hr><h3 id="Gym-打包脚本文件"><a href="#Gym-打包脚本文件" class="headerlink" title="Gym 打包脚本文件"></a>Gym 打包脚本文件</h3><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><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></pre></td><td class="code"><pre><span class="line">#!/bin/bash</span><br><span class="line"></span><br><span class="line">#计时</span><br><span class="line">SECONDS=0</span><br><span class="line"></span><br><span class="line">#假设脚本放置在与项目相同的路径下</span><br><span class="line">project_path=$(pwd)</span><br><span class="line">#取当前时间字符串添加到文件结尾</span><br><span class="line">now=$(date +&quot;%Y_%m_%d_%H_%M_%S&quot;)</span><br><span class="line"></span><br><span class="line">#指定项目的scheme名称</span><br><span class="line">scheme=&quot;DemoScheme&quot;</span><br><span class="line">#指定要打包的配置名</span><br><span class="line">configuration=&quot;Adhoc&quot;</span><br><span class="line">#指定打包所使用的输出方式，目前支持app-store, package, ad-hoc, enterprise, development, 和developer-id，即xcodebuild的method参数</span><br><span class="line">export_method=&#x27;ad-hoc&#x27;</span><br><span class="line"></span><br><span class="line">#指定项目地址</span><br><span class="line">workspace_path=&quot;$project_path/Demo.xcworkspace&quot;</span><br><span class="line">#指定输出路径</span><br><span class="line">output_path=&quot;/Users/your_username/Documents/&quot;</span><br><span class="line">#指定输出归档文件地址</span><br><span class="line">archive_path=&quot;$output_path/Demo_$&#123;now&#125;.xcarchive&quot;</span><br><span class="line">#指定输出ipa地址</span><br><span class="line">ipa_path=&quot;$output_path/Demo_$&#123;now&#125;.ipa&quot;</span><br><span class="line">#指定输出ipa名称</span><br><span class="line">ipa_name=&quot;Demo_$&#123;now&#125;.ipa&quot;</span><br><span class="line">#获取执行命令时的commit message</span><br><span class="line">commit_msg=&quot;$1&quot;</span><br><span class="line"></span><br><span class="line">#输出设定的变量值</span><br><span class="line">echo &quot;===workspace path: $&#123;workspace_path&#125;===&quot;</span><br><span class="line">echo &quot;===archive path: $&#123;archive_path&#125;===&quot;</span><br><span class="line">echo &quot;===ipa path: $&#123;ipa_path&#125;===&quot;</span><br><span class="line">echo &quot;===export method: $&#123;export_method&#125;===&quot;</span><br><span class="line">echo &quot;===commit msg: $1===&quot;</span><br><span class="line"></span><br><span class="line">#先清空前一次build</span><br><span class="line">gym --workspace $&#123;workspace_path&#125; --scheme $&#123;scheme&#125; --clean --configuration $&#123;configuration&#125; --archive_path $&#123;archive_path&#125; --export_method $&#123;export_method&#125; --output_directory $&#123;output_path&#125; --output_name $&#123;ipa_name&#125;</span><br><span class="line"></span><br><span class="line">#上传到fir</span><br><span class="line">fir publish $&#123;ipa_path&#125; -T fir_token -c &quot;$&#123;commit_msg&#125;&quot;</span><br><span class="line"></span><br><span class="line">#输出总用时</span><br><span class="line">echo &quot;===Finished. Total time: $&#123;SECONDS&#125;s===&quot;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="xctool-打包脚本文件"><a href="#xctool-打包脚本文件" class="headerlink" title="xctool 打包脚本文件"></a>xctool 打包脚本文件</h3><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><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><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/bash</span><br><span class="line"></span><br><span class="line">#计时</span><br><span class="line">SECONDS=0</span><br><span class="line"></span><br><span class="line">#假设脚本放置在与项目相同的路径下</span><br><span class="line">project_path=$(pwd)</span><br><span class="line">#取当前时间字符串添加到文件结尾</span><br><span class="line">now=$(date +&quot;%Y_%m_%d_%H_%M_%S&quot;)</span><br><span class="line"></span><br><span class="line">#指定项目的scheme名称</span><br><span class="line">scheme=&quot;DemoScheme&quot;</span><br><span class="line">#指定要打包的配置名</span><br><span class="line">configuration=&quot;Adhoc&quot;</span><br><span class="line">#指定打包所使用的provisioning profile名称</span><br><span class="line">provisioning_profile=&#x27;AdHoc Profile&#x27;</span><br><span class="line"></span><br><span class="line">#指定项目地址</span><br><span class="line">workspace_path=&quot;$project_path/Demo.xcworkspace&quot;</span><br><span class="line">#指定输出路径</span><br><span class="line">output_path=&quot;/Users/your_username/Documents/&quot;</span><br><span class="line">#指定输出归档文件地址</span><br><span class="line">archive_path=&quot;$output_path/Demo_$&#123;now&#125;.xcarchive&quot;</span><br><span class="line">#指定输出ipa地址</span><br><span class="line">ipa_path=&quot;$output_path/Demo_$&#123;now&#125;.ipa&quot;</span><br><span class="line">#获取执行命令时的commit message</span><br><span class="line">commit_msg=&quot;$1&quot;</span><br><span class="line"></span><br><span class="line">#输出设定的变量值</span><br><span class="line">echo &quot;===workspace path: $&#123;workspace_path&#125;===&quot;</span><br><span class="line">echo &quot;===archive path: $&#123;archive_path&#125;===&quot;</span><br><span class="line">echo &quot;===ipa path: $&#123;ipa_path&#125;===&quot;</span><br><span class="line">echo &quot;===profile: $&#123;provisioning_profile&#125;===&quot;</span><br><span class="line">echo &quot;===commit msg: $1===&quot;</span><br><span class="line"></span><br><span class="line">#先清空前一次build</span><br><span class="line">xctool clean -workspace $&#123;workspace_path&#125; -scheme $&#123;scheme&#125; -configuration $&#123;configuration&#125;</span><br><span class="line"></span><br><span class="line">#根据指定的项目、scheme、configuration与输出路径打包出archive文件</span><br><span class="line">xctool build -workspace $&#123;workspace_path&#125; -scheme $&#123;scheme&#125; -configuration $&#123;configuration&#125; archive -archivePath $&#123;archive_path&#125;</span><br><span class="line"></span><br><span class="line">#使用指定的provisioning profile导出ipa</span><br><span class="line">#我暂时没找到xctool指定provisioning profile的方法，所以这里用了xcodebuild</span><br><span class="line">xcodebuild -exportArchive -archivePath $&#123;archive_path&#125; -exportPath $&#123;ipa_path&#125; -exportFormat ipa -exportProvisioningProfile &quot;$&#123;provisioning_profile&#125;&quot;</span><br><span class="line"></span><br><span class="line">#上传到fir</span><br><span class="line">fir publish $&#123;ipa_path&#125; -T fir_token -c &quot;$&#123;commit_msg&#125;&quot;</span><br><span class="line"></span><br><span class="line">#输出总用时</span><br><span class="line">echo &quot;===Finished. Total time: $&#123;SECONDS&#125;s===&quot;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="概念补充"><a href="#概念补充" class="headerlink" title="概念补充"></a>概念补充</h3><ol><li><p><code>*.workspace </code> 文件<br>使用CocoaPods管理的工程在执行完 <code>pod install</code> 之后生成的workspace文件</p></li><li><p>scheme<br>显示在Xcode的左上角，run图标的右边，设备选择的左边</p></li><li><p>configuration<br>在Xcode中选项目，Info tab下会列出所有的configuration，一般有Debug和Release两种</p></li><li><p>provisioning profile<br>在Xcode中选target，在 <code>Build Settings tab</code> 下搜索 <code>Provisioning Profile </code>，默认应该是 <code>Automatic </code> ，点击看到下拉列表中的就是所有可用的名称</p></li></ol><hr><h2 id="升级-Ruby-版本"><a href="#升级-Ruby-版本" class="headerlink" title="升级 Ruby 版本"></a>升级 Ruby 版本</h2><p>1、安装 Rvm （第三方工具）</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">$ curl -L get.rvm.io | bash -s stable</span><br><span class="line">$ source ~/.rvm/scripts/rvm </span><br></pre></td></tr></table></figure><p>等待终端加载完毕,后输入：</p><p><code>rvm -v </code></p><p>如果显示版本号，则安装成功~</p><p>2、安装 Ruby</p><p>· 列出所有 Ruby 可安装版本的信息<br><code>rvm list known </code></p><p>· 安装一个 Ruby 版本<br><code>rvm install 2.1.4 </code></p><p>如果想设置为默认版本，可以用这条命令来完成</p><p><code>rvm use 2.1.4 --default  </code></p><p>· 查看已安装的 Ruby<br><code>rvm list </code></p><p>· 卸载一个已安装 Ruby 版本<br><code>rvm remove 2.1.4 </code></p><p>3、更换源</p><p>· 查看已有源<br><code>gem source </code></p><p>· 由于国内被墙，所以我们需要更换源至 <a href="https://ruby.taobao.org/">淘宝服务器</a> 或 <a href="https://gems.ruby-china.org/">Ruby China</a></p><blockquote><p> 淘宝 <a href="https://ruby.taobao.org/">https://ruby.taobao.org</a><br> Ruby China <a href="https://gems.ruby-china.org/">https://gems.ruby-china.org/</a></p></blockquote><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></pre></td><td class="code"><pre><span class="line">$ gem update --system</span><br><span class="line">$ gem uninstall rubygems-update</span><br><span class="line">$ gem sources -r http://rubygems.org/</span><br><span class="line">$ gem sources -a http://ruby.taobao.org</span><br></pre></td></tr></table></figure><hr><h2 id="gem-常用命令"><a href="#gem-常用命令" class="headerlink" title="gem 常用命令"></a>gem 常用命令</h2><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><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></pre></td><td class="code"><pre><span class="line">ruby -v #查看ruby 版本</span><br><span class="line"></span><br><span class="line">ruby -e &#x27;&#x27;require&quot;watir&quot;; puts Watir::IE::VERSION&#x27;&#x27;　#查看watir版本</span><br><span class="line">gem -v #gem版本</span><br><span class="line">gem update #更新所有包</span><br><span class="line">gem update --system #更新RubyGems软件</span><br><span class="line">gem install rake #安装rake,从本地或远程服务器</span><br><span class="line">gem install rake --remote #安装rake,从远程服务器</span><br><span class="line">gem install watir -v(或者--version) 1.6.2#指定安装版本的</span><br><span class="line">gem uninstall rake #卸载rake包</span><br><span class="line">gem list d #列出本地以d打头的包</span><br><span class="line">gem query -n &#x27;&#x27;[0-9]&#x27;&#x27; --local #查找本地含有数字的包</span><br><span class="line">gem search log --both #从本地和远程服务器上查找含有log字符串的包</span><br><span class="line">gem search log --remoter #只从远程服务器上查找含有log字符串的包</span><br><span class="line">gem search -r log #只从远程服务器上查找含有log字符串的包</span><br><span class="line">gem help #提醒式的帮助</span><br><span class="line">gem help install #列出install命令 帮助</span><br><span class="line">gem help examples #列出gem命令使用一些例子</span><br><span class="line">gem build rake.gemspec #把rake.gemspec编译成rake.gem</span><br><span class="line">gem check -v pkg/rake-0.4.0.gem #检测rake是否有效</span><br><span class="line">gem cleanup #清除所有包旧版本，保留最新版本</span><br><span class="line">gem contents rake #显示rake包中所包含的文件</span><br><span class="line">gem dependency rails -v 0.10.1 #列出与rails相互依赖的包</span><br><span class="line">gem environment #查看gem的环境</span><br><span class="line"></span><br></pre></td></tr></table></figure><h6 id="文章引用"><a href="#文章引用" class="headerlink" title="文章引用"></a>文章引用</h6><blockquote><p><a href="http://www.jianshu.com/p/54ab07f2e63b">http://www.jianshu.com/p/54ab07f2e63b</a><br><a href="http://www.07net01.com/2015/09/933234.html">http://www.07net01.com/2015/09/933234.html</a><br><a href="https://my.oschina.net/u/923974/blog/99060">https://my.oschina.net/u/923974/blog/99060</a></p></blockquote>]]></content>
    
    
    <summary type="html">脚本文件自动化打包</summary>
    
    
    
    <category term="iOS" scheme="https://rmb.ma/categories/iOS/"/>
    
    
    <category term="脚本，自动化" scheme="https://rmb.ma/tags/%E8%84%9A%E6%9C%AC%EF%BC%8C%E8%87%AA%E5%8A%A8%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>Hexo搭建</title>
    <link href="https://rmb.ma/posts/Hexo/2016-08-25-Hexo%E6%90%AD%E5%BB%BA.html"/>
    <id>https://rmb.ma/posts/Hexo/2016-08-25-Hexo%E6%90%AD%E5%BB%BA.html</id>
    <published>2016-08-25T09:27:30.000Z</published>
    <updated>2020-01-13T11:05:08.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="1、环境配置"><a href="#1、环境配置" class="headerlink" title="1、环境配置"></a>1、环境配置</h2><h3 id="1-1-Git"><a href="#1-1-Git" class="headerlink" title="1.1 Git"></a>1.1 Git</h3><p>Mac已内置</p><h3 id="1-2-Nodejs"><a href="#1-2-Nodejs" class="headerlink" title="1.2 Nodejs"></a>1.2 Nodejs</h3><p>官网下载 <a href="http://nodejs.org/">http://nodejs.org/</a><br>默认安装即可</p><h2 id="2、安装Hexo"><a href="#2、安装Hexo" class="headerlink" title="2、安装Hexo"></a>2、安装Hexo</h2><blockquote><p>参考官网 <a href="https://hexo.io/">https://hexo.io/</a></p></blockquote><h3 id="2-1-npm-安装Hexo"><a href="#2-1-npm-安装Hexo" class="headerlink" title="2.1 npm 安装Hexo"></a>2.1 npm 安装Hexo</h3><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">$ npm install -g hexo-cli</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>安装完成后，指定路径新建所需文件</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></pre></td><td class="code"><pre><span class="line">$ hexo init &lt;folder&gt;</span><br><span class="line">$ cd &lt;folder&gt;</span><br><span class="line">$ npm install</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>完成后，目录文件结构如下</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><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">├── _config.yml// 网站的配置信息</span><br><span class="line">├── package.json// 应用程序的信息</span><br><span class="line">├── scaffolds// 模板文件夹, 新建文章时根据模板生成文件</span><br><span class="line">├── source// 资源文件，Markdown 和 HTML 文件会被解析并放到 public 文件夹</span><br><span class="line">|   ├── _drafts</span><br><span class="line">|   └── _posts</span><br><span class="line">└── themes// 主题文件夹</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>注：npm 时报错，可能是网络问题，可使用代理或使用 <a href="https://npm.taobao.org/">淘宝NPM镜像</a></p><p>启动server</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">hexo server</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="2-2-config-yml-配置"><a href="#2-2-config-yml-配置" class="headerlink" title="2.2 _config.yml 配置"></a>2.2 _config.yml 配置</h3><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><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><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">fancybox: true ## If you want to use fancybox please set the value to true.</span><br><span class="line">duoshuo: ## Your duoshuo_shortname, e.g. username</span><br><span class="line">disqus: ## Your disqus_shortname, e.g. username</span><br><span class="line">google_search: true ## Use Google search, true/false.</span><br><span class="line">baidu_search: ## Use Baidu search, true/false.</span><br><span class="line">swiftype: ## Your swiftype_key, e.g. m7b11ZrsT8Me7gzApciT</span><br><span class="line">tinysou: ## Your tinysou_key, e.g. 4ac092ad8d749fdc6293</span><br><span class="line">self_search: ## Use a jQuery-based local search engine, true/false.</span><br><span class="line">google_analytics: ## Your Google Analytics tracking id, e.g. UA-42425684-2</span><br><span class="line">baidu_analytics: ## Your Baidu Analytics tracking id, e.g. 8006843039519956000</span><br><span class="line">show_category_count: false ## If you want to show the count of categories in the sidebar widget please set the value to true.</span><br><span class="line">shareto: true ## If you want to use the share button please set the value to true.</span><br><span class="line">busuanzi: true ## If you want to use Busuanzi page views please set the value to true.</span><br><span class="line">widgets_on_small_screens: false ## Set to true to enable widgets on small screens.</span><br><span class="line">menu:</span><br><span class="line">  - page: home</span><br><span class="line">    directory: .</span><br><span class="line">    icon: fa-home</span><br><span class="line">  - page: archive</span><br><span class="line">    directory: archives/</span><br><span class="line">    icon: fa-archive</span><br><span class="line">  - page: about</span><br><span class="line">    directory: about/</span><br><span class="line">    icon: fa-user</span><br><span class="line">  - page: rss</span><br><span class="line">    directory: atom.xml</span><br><span class="line">    icon: fa-rss</span><br><span class="line">widgets: ## Six widgets in sidebar provided: search, category, tag, recent_posts, rencent_comments and links.</span><br><span class="line">  - search</span><br><span class="line">  - category</span><br><span class="line">  - tag</span><br><span class="line">  - recent_posts</span><br><span class="line">  - recent_comments</span><br><span class="line">  - links</span><br><span class="line">links:</span><br><span class="line">  - title: site-name1</span><br><span class="line">    url: http://www.example1.com/</span><br><span class="line">  - title: site-name2</span><br><span class="line">    url: http://www.example2.com/</span><br><span class="line">  - title: site-name3</span><br><span class="line">    url: http://www.example3.com/</span><br><span class="line">    </span><br><span class="line">timeline:</span><br><span class="line">  - num: 1</span><br><span class="line">    word: 2014/06/12-Start</span><br><span class="line">  - num: 2</span><br><span class="line">    word: 2014/11/29-XXX</span><br><span class="line">  - num: 3</span><br><span class="line">    word: 2015/02/18-DDD</span><br><span class="line">  - num: 4</span><br><span class="line">    word: More</span><br><span class="line">    </span><br><span class="line"> # Static files</span><br><span class="line">js: js</span><br><span class="line">css: css</span><br><span class="line"> # Theme version</span><br><span class="line">version: 0.0.0</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>fancybox - 是否启用Fancybox图片灯箱效果</li><li>duoshuo - 多说评论 shortname</li><li>disqus - Disqus评论 shortname</li><li>google_search - 默认使用Google搜索引擎</li><li>baidu_search - 若想使用百度搜索，将其设定为true。</li><li>swiftype - Swiftype 站内搜索key</li><li>tinysou - 微搜索 key</li><li>self_search - 基于jQuery的本地搜索引擎，需要安装hexo-generator-search插件使用。</li><li>google_analytics - Google Analytics 跟踪ID</li><li>baidu_analytics - 百度统计 跟踪ID</li><li>show_category_count - 是否显示侧边栏分类数目</li><li>shareto - 是否使用分享按鈕</li><li>busuanzi - 是否使用不蒜子页面访问计数</li><li>widgets_on_small_screens - 是否在移动设备屏幕底部显示侧边栏</li><li>menu - 自定义页面及菜单，依照已有格式填写。填写后请在source目录下建立相应名称的文件夹，并包含index.md文件，以正确显示页面。导航菜单中集成了FontAwesome图标字体，可以在这里选择新的图标，并按照相关说明使用。</li><li>widgets - 选择和排列希望使用的侧边栏小工具。</li><li>links - 友情链接，请依照格式填写。</li><li>timeline - 网站历史时间线，在页面front-matter中设置layout: timeline可显示。</li><li>Static files - 静态文件存储路径，方便设置CDN缓存。</li><li>Theme version - 主题版本，便于静态文件更新后刷新CDN缓存。</li></ul><h3 id="3-3-主题安装"><a href="#3-3-主题安装" class="headerlink" title="3.3 主题安装"></a>3.3 主题安装</h3><blockquote><p>官网主题<a href="https://hexo.io/themes/">列表</a></p></blockquote><p>1、Git Clone 到  <code>themes</code>  文件下</p><p>2、安装渲染器</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></pre></td><td class="code"><pre><span class="line">$ npm install hexo-renderer-jade --save</span><br><span class="line">$ npm install hexo-renderer-sass --save</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>3、编辑Hexo目录下的 <code>_config.yml </code>，将 <code>theme</code> 的值改为 <code>maupassant</code> 。</p><h2 id="3、新建文章"><a href="#3、新建文章" class="headerlink" title="3、新建文章"></a>3、新建文章</h2><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">hexo new &quot;postName&quot;</span><br><span class="line"></span><br></pre></td></tr></table></figure><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">hexo new page  &quot;pageName&quot; </span><br><span class="line"></span><br></pre></td></tr></table></figure><p>生成静态页面至 <code>public</code> 目录<br><code>hexo generate </code></p><p>配置文章 <code>front-matter</code> </p><ul><li>标签 <code>tags:</code></li><li>分类 <code>categories:</code></li><li>是否显示评论 <code>comments:</code></li><li>摘要（列表显示的内容）<code>description:</code></li><li>是否显示目录<code>toc:</code></li></ul><p>注：<code> ：</code> 后 内容之前 必须加一个 空格，否则生成文章时会报错。</p><h2 id="4、部署Github"><a href="#4、部署Github" class="headerlink" title="4、部署Github"></a>4、部署Github</h2><p>配置Github仓库</p><p>仓库名 <code>your_user_name.github.io</code> 格式，严格遵守</p><p>修改 <code>_config.yml</code> </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><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># Deployment</span><br><span class="line">## Docs: https://hexo.io/docs/deployment.html</span><br><span class="line">deploy:</span><br><span class="line">  type: git</span><br><span class="line">  repo: git@github.com:mayuan607/mayuan607.github.io.git</span><br><span class="line">  branch: master  </span><br><span class="line">  </span><br></pre></td></tr></table></figure><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">npm install hexo-deployer-git --save</span><br><span class="line"></span><br></pre></td></tr></table></figure><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">hexo deploy</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>浏览器打开 <code>your_user_name.github.io</code> ,正常访问 部署完成。</p><p>之后，每次部署均是三个步骤</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></pre></td><td class="code"><pre><span class="line">$ hexo clean</span><br><span class="line">$ hexo generate</span><br><span class="line">$ hexo deploy</span><br><span class="line">   </span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">Hexo搭建Github博客</summary>
    
    
    
    <category term="Hexo" scheme="https://rmb.ma/categories/Hexo/"/>
    
    
    <category term="Hexo" scheme="https://rmb.ma/tags/Hexo/"/>
    
  </entry>
  
  <entry>
    <title>Xcode更新插件失效</title>
    <link href="https://rmb.ma/posts/iOS/2016-08-23-Xcode%E6%9B%B4%E6%96%B0%E6%8F%92%E4%BB%B6%E5%A4%B1%E6%95%88.html"/>
    <id>https://rmb.ma/posts/iOS/2016-08-23-Xcode%E6%9B%B4%E6%96%B0%E6%8F%92%E4%BB%B6%E5%A4%B1%E6%95%88.html</id>
    <published>2016-08-23T11:24:45.000Z</published>
    <updated>2018-06-19T08:21:49.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="提示：从-Xcode8-开始，已经不再支持三方插件！"><a href="#提示：从-Xcode8-开始，已经不再支持三方插件！" class="headerlink" title="提示：从 Xcode8 开始，已经不再支持三方插件！"></a>提示：从 Xcode8 开始，已经不再支持三方插件！</h3><blockquote><p>每次Xcode更新后，就会发现，我靠我的插件怎么都没了？现在好了，两行命令帮你搞定一切！</p></blockquote><hr><blockquote><p>原因：每个版本的Xcode会有一个唯一的DVTPlugInCompatibilityUUID，当你在新安装一个插件的时候，会将你当前Xcode的DVTPlugInCompatibilityUUID加入到插件对应的plist文件中。Xcode更新后DVTPlugInCompatibilityUUID改变，插件不能识别，所以我们只要拿到当前新版Xcode的DVTPlugInCompatibilityUUID 重新写入就OK了。</p></blockquote><h1 id="打开终端"><a href="#打开终端" class="headerlink" title="打开终端"></a>打开终端</h1><h2 id="1-获取UUID"><a href="#1-获取UUID" class="headerlink" title="1.获取UUID"></a>1.获取UUID</h2><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">$defaults read /Applications/Xcode.app/Contents/Info DVTPlugInCompatibilityUUID</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这行命令是用来获取你Xcode的DVTPlugInCompatibilityUUID</p><h2 id="2-将UUID重新加入你的插件"><a href="#2-将UUID重新加入你的插件" class="headerlink" title="2.将UUID重新加入你的插件"></a>2.将UUID重新加入你的插件</h2><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">$ find ~/Library/Application\ Support/Developer/Shared/Xcode/Plug-ins -name Info.plist -maxdepth 3 | xargs -I&#123;&#125; defaults write &#123;&#125; DVTPlugInCompatibilityUUIDs -array-add UUID码</span><br></pre></td></tr></table></figure><p>注：将第一步获取到的UUID替换到第二步命令 <code>UUID码</code> 的位置</p><h2 id="3-搞定"><a href="#3-搞定" class="headerlink" title="3.搞定"></a>3.搞定</h2><p><img src="http://obdrd2vaq.bkt.clouddn.com/854431-cf0a97062b2304f5.png" alt="屏幕快照 2016-01-07 下午5.06.19.png"></p>]]></content>
    
    
    <summary type="html">两行命令，解决Xcode更新后插件失效的问题</summary>
    
    
    
    <category term="iOS" scheme="https://rmb.ma/categories/iOS/"/>
    
    
    <category term="iOS" scheme="https://rmb.ma/tags/iOS/"/>
    
  </entry>
  
</feed>
