<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Jason&#39;s Blog</title>
  
  <subtitle>A passionate software engineer</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://jasonhan1990.github.io/"/>
  <updated>2019-05-08T00:49:08.000Z</updated>
  <id>https://jasonhan1990.github.io/</id>
  
  <author>
    <name>Juncheng Han</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Introducing  JCCloudProgressView</title>
    <link href="https://jasonhan1990.github.io/2019/05/07/JCCloudProgessView/"/>
    <id>https://jasonhan1990.github.io/2019/05/07/JCCloudProgessView/</id>
    <published>2019-05-08T00:39:42.000Z</published>
    <updated>2019-05-08T00:49:08.000Z</updated>
    
    <content type="html"><![CDATA[<p>JCCloudProgressView is a gorgeous progress indicator that you wish your internet could be slower.<br><a id="more"></a></p><p>During my recent iOS app development, I am working on a project that needs to send large images to our server for image processing.</p><p>The data transferring could be slow if our customers are under a pool quality internet environment. We wish this boring process could be pleasing for our customers, so we focused a little bit more on our UI designs.</p><div class="figure center" style="width:;"><a class="fancybox" href="cloud.gif" title="JCCloudProgressView" data-caption="JCCloudProgressView" data-fancybox="default"><img class="fig-img" src="cloud.gif" alt="JCCloudProgressView"></a><span class="caption">JCCloudProgressView</span></div><iframe src="https://www.youtube.com/embed/sGYuJqRcM9U" width="100%" height="568px" frameborder="0" allowfullscreen></iframe><p>If you like it, you can find it on Cocoapods.org and my GitHub page.<br><a href="https://cocoapods.org/pods/JCCloudProgressView" target="_blank" rel="noopener">https://cocoapods.org/pods/JCCloudProgressView</a><br><a href="https://github.com/JasonHan1990/JCCloudProgressView" target="_blank" rel="noopener">https://github.com/JasonHan1990/JCCloudProgressView</a></p><p>Feel free to point out any coding errors. I love to learn from you guys.<br>Thanks!!</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;JCCloudProgressView is a gorgeous progress indicator that you wish your internet could be slower.&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="Objective C" scheme="https://jasonhan1990.github.io/tags/Objective-C/"/>
    
  </entry>
  
  <entry>
    <title>My first chrome extension - College Data Scraper</title>
    <link href="https://jasonhan1990.github.io/2019/03/28/my-first-chrome-extension/"/>
    <id>https://jasonhan1990.github.io/2019/03/28/my-first-chrome-extension/</id>
    <published>2019-03-29T06:08:46.000Z</published>
    <updated>2019-04-16T18:11:01.000Z</updated>
    
    <content type="html"><![CDATA[<p>I wrote a chrome extension to scrape college admission data.<br><a id="more"></a></p><p>Recently, I am working on a project about training a model to predict the result of college admission. Me and my teammate, we are searching for data from <a href="https://www.collegedata.com" target="_blank" rel="noopener">https://www.collegedata.com</a>. Unfortunately, the website doesn’t offer data downloading. So I started to write a program to scrape the data.<br>My first implementation was using Cheerio (<a href="https://github.com/cheeriojs/cheerio)" target="_blank" rel="noopener">https://github.com/cheeriojs/cheerio)</a>, a NodeJS framework that is good at parsing and searching HTML nodes.<br>However, I need to hand typing a bunch of variables as inputs to my program. And for my teammate, it was not convenient for him to use. He needed to install NodeJS and know some basic knowledge of how NodeJS works.</p><p>My second implementation was to create a chrome extension and use jQuery to scrape the data. Then, I packed the extension and sent it to my teammate to install and use it.</p><p>Since it is not a commercial extension. I was keeping things simple.</p><h3 id="Files"><a href="#Files" class="headerlink" title="Files"></a>Files</h3><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-28%20at%2011.39.39%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-28%20at%2011.39.39%20PM.png" alt></a></div><ul><li>manifest.json: All the configuration of your extension.</li><li>content.js: My code that creates UI and scrapes the data.</li><li>FileSaver.js: Use it to save the data as a file. (<a href="https://github.com/eligrey/FileSaver.js/" target="_blank" rel="noopener">https://github.com/eligrey/FileSaver.js/</a>)</li></ul><h4 id="manifest-json"><a href="#manifest-json" class="headerlink" title="manifest.json"></a>manifest.json</h4><figure class="highlight json"><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">&#123;</span><br><span class="line">    <span class="attr">"manifest_version"</span>: <span class="number">2</span>,</span><br><span class="line">    <span class="attr">"name"</span>: <span class="string">"Collegedata-Srcaper"</span>,</span><br><span class="line">    <span class="attr">"version"</span>: <span class="string">"0.1"</span>,</span><br><span class="line">    <span class="attr">"content_scripts"</span>: [</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="attr">"matches"</span>: [</span><br><span class="line">            <span class="string">"https://www.collegedata.com/*"</span></span><br><span class="line">          ],</span><br><span class="line">          <span class="attr">"js"</span>: [<span class="string">"jquery-3.3.1.min.js"</span>,<span class="string">"FileSaver.js"</span>, <span class="string">"content.js"</span>]</span><br><span class="line">        &#125;</span><br><span class="line">    ],</span><br><span class="line">    <span class="attr">"browser_action"</span>: &#123;</span><br><span class="line">        <span class="attr">"default_icon"</span>: <span class="string">"icon.png"</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>For “js” section, the order is important. Chrome loads them sequentially. So, the libs need to load first.</p><h3 id="Install-and-pack-your-extension"><a href="#Install-and-pack-your-extension" class="headerlink" title="Install and pack your extension"></a>Install and pack your extension</h3><p>Go to chrome -&gt; extension. Toggle the developer mode. Then load unpacked extention.<br><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-28%20at%2011.52.38%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-28%20at%2011.52.38%20PM.png" alt></a></div><br><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-28%20at%2011.52.57%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-28%20at%2011.52.57%20PM.png" alt></a></div></p><h3 id="Screenshots"><a href="#Screenshots" class="headerlink" title="Screenshots"></a>Screenshots</h3><p>After installing the extension, in the <a href="https://www.collegedata.com" target="_blank" rel="noopener">https://www.collegedata.com</a> website, a floating bar appears on the top left corner.</p><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-28%20at%2011.49.30%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-28%20at%2011.49.30%20PM.png" alt></a></div><p>The extension works when there are data on the page. Otherwise, it just alerts you “No data found”.</p><p>So, go the admission tracking page, and type in the university and years that you want to look at. Here, I typed in Stanford, and year from 2010 to 2020.</p><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-28%20at%2011.50.13%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-28%20at%2011.50.13%20PM.png" alt></a></div><p>Once the data are retrieved from server. Click “Download” button. Then, save the data.csv file to your desktop.</p><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-29%20at%2012.08.25%20AM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-29%20at%2012.08.25%20AM.png" alt></a></div><p>Open with Office Excel.</p><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-29%20at%2012.30.33%20AM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-29%20at%2012.30.33%20AM.png" alt></a></div><h3 id="Bravo"><a href="#Bravo" class="headerlink" title="Bravo!!!"></a>Bravo!!!</h3><p>Link to the code: <a href="https://bitbucket.org/JunchengHan/collegedata-scraper-extension/src" target="_blank" rel="noopener">https://bitbucket.org/JunchengHan/collegedata-scraper-extension/src</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;I wrote a chrome extension to scrape college admission data.&lt;br&gt;
    
    </summary>
    
      <category term="Web" scheme="https://jasonhan1990.github.io/categories/Web/"/>
    
    
      <category term="javascript" scheme="https://jasonhan1990.github.io/tags/javascript/"/>
    
      <category term="chrome extension" scheme="https://jasonhan1990.github.io/tags/chrome-extension/"/>
    
  </entry>
  
  <entry>
    <title>Correctly using custom fonts in XCode</title>
    <link href="https://jasonhan1990.github.io/2019/03/20/ios-ui-dev-001/"/>
    <id>https://jasonhan1990.github.io/2019/03/20/ios-ui-dev-001/</id>
    <published>2019-03-20T22:27:42.000Z</published>
    <updated>2019-03-20T22:47:31.000Z</updated>
    
    <content type="html"><![CDATA[<p>There are several steps needed before you can successfully use your custom fonts in your iOS app.<br><a id="more"></a></p><h3 id="Step-1"><a href="#Step-1" class="headerlink" title="Step 1:"></a>Step 1:</h3><p><strong>Drag your fonts into XCode project, and make sure each of them is included in the target</strong><br><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-20%20at%203.03.46%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-20%20at%203.03.46%20PM.png" alt></a></div><br><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-20%20at%203.05.47%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-20%20at%203.05.47%20PM.png" alt></a></div></p><h3 id="Step-2"><a href="#Step-2" class="headerlink" title="Step 2:"></a>Step 2:</h3><p><strong>Double check that your fonts are in the Resource Bundle</strong><br>Select your target -&gt; Build Phases -&gt; Copy Bundle Resources<br><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-20%20at%203.09.25%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-20%20at%203.09.25%20PM.png" alt></a></div></p><h3 id="Step-3"><a href="#Step-3" class="headerlink" title="Step 3:"></a>Step 3:</h3><p><strong>Add your fonts to application plist</strong><br><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-20%20at%203.14.42%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-20%20at%203.14.42%20PM.png" alt></a></div></p><h3 id="Step-4"><a href="#Step-4" class="headerlink" title="Step 4:"></a>Step 4:</h3><p><strong>Check the fonts names</strong><br>The font file downloaded from internet might be differ from the font name itself. You can check the font name with following codes:<br><strong>Objective-C</strong></p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span> (<span class="built_in">NSString</span> * fontFamilyName <span class="keyword">in</span> <span class="built_in">UIFont</span>.familyNames) &#123;</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"%@"</span>, fontFamilyName);</span><br><span class="line">    <span class="keyword">for</span> (<span class="built_in">NSString</span> * fontName <span class="keyword">in</span> [<span class="built_in">UIFont</span> fontNamesForFamilyName:fontFamilyName]) &#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@"|-%@"</span>, fontName);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><div class="figure center" style="width:;"><a class="fancybox" href="Screen%20Shot%202019-03-20%20at%203.21.37%20PM.png" title data-caption data-fancybox="default"><img class="fig-img" src="Screen%20Shot%202019-03-20%20at%203.21.37%20PM.png" alt></a></div><p><strong>Swift</strong><br><figure class="highlight swift"><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"><span class="keyword">for</span> family <span class="keyword">in</span> <span class="type">UIFont</span>.familyNames.sorted() &#123;</span><br><span class="line">    <span class="keyword">let</span> names = <span class="type">UIFont</span>.fontNames(forFamilyName: family)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">"Family: <span class="subst">\(family)</span> Font names: <span class="subst">\(names)</span>"</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p><h3 id="Step-5"><a href="#Step-5" class="headerlink" title="Step 5:"></a>Step 5:</h3><p>Finally, use your custom fonts.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;There are several steps needed before you can successfully use your custom fonts in your iOS app.&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="Swift" scheme="https://jasonhan1990.github.io/tags/Swift/"/>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="Objective-C" scheme="https://jasonhan1990.github.io/tags/Objective-C/"/>
    
      <category term="UIFont" scheme="https://jasonhan1990.github.io/tags/UIFont/"/>
    
      <category term="UI Development" scheme="https://jasonhan1990.github.io/tags/UI-Development/"/>
    
  </entry>
  
  <entry>
    <title>unsafe_unretained vs. weak</title>
    <link href="https://jasonhan1990.github.io/2019/03/03/objc-mem-management-01/"/>
    <id>https://jasonhan1990.github.io/2019/03/03/objc-mem-management-01/</id>
    <published>2019-03-03T21:17:39.000Z</published>
    <updated>2019-03-03T22:02:53.000Z</updated>
    
    <content type="html"><![CDATA[<p>They are both representing the nonowning relationship.<br>But the diffrence is:<br><a id="more"></a></p><p>When the <code>unsafe_unretained</code> object is recycled by ARC, the property is still pointing to the object. If we are calling the property, the system will crash.<br>However, when the <code>weak</code> object is recycled by ARC, the property will be set to nil. If we are calling the property, of course nothing will happen, but the system won’t crash.<br>That is why <code>weak</code> is safer than <code>unsafe_unretained</code>.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;They are both representing the nonowning relationship.&lt;br&gt;But the diffrence is:&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="Objective-C" scheme="https://jasonhan1990.github.io/tags/Objective-C/"/>
    
  </entry>
  
  <entry>
    <title>CaseIterable from Swift 4.2</title>
    <link href="https://jasonhan1990.github.io/2019/02/06/swift-new-feature-1/"/>
    <id>https://jasonhan1990.github.io/2019/02/06/swift-new-feature-1/</id>
    <published>2019-02-07T07:02:34.000Z</published>
    <updated>2019-02-07T07:15:55.000Z</updated>
    
    <content type="html"><![CDATA[<p>The new CaseIterable protocol gives your Enum new ability to generate an array of all cases in an enum.</p><a id="more"></a><p>Pasta example from <a href="https://www.hackingwithswift.com/articles/77/whats-new-in-swift-4-2" target="_blank" rel="noopener">https://www.hackingwithswift.com/articles/77/whats-new-in-swift-4-2</a></p><figure class="highlight swift"><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"><span class="class"><span class="keyword">enum</span> <span class="title">Pasta</span>: <span class="title">CaseIterable</span> </span>&#123;</span><br><span class="line"><span class="keyword">case</span> cannelloni, fusilli, linguine, tagliatelle</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> pasta <span class="keyword">in</span> <span class="type">Pasta</span>.allCases &#123;</span><br><span class="line"><span class="built_in">print</span>(pasta)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Print out:</p><figure class="highlight bash"><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">cannelloni</span><br><span class="line">fusilli</span><br><span class="line">linguine</span><br><span class="line">tagliatelle</span><br></pre></td></tr></table></figure><p>Then you can easily generate data for table view.</p><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">Pasta</span>: <span class="title">CaseIterable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">case</span> conchiglie, fusilli, linguine, tagliatelle</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> name: <span class="type">String</span> &#123;</span><br><span class="line">        <span class="keyword">switch</span> <span class="keyword">self</span> &#123;</span><br><span class="line">        <span class="keyword">case</span> .conchiglie: <span class="keyword">return</span> <span class="string">"Conchiglie"</span></span><br><span class="line">        <span class="keyword">case</span> .fusilli: <span class="keyword">return</span> <span class="string">"Fusilli"</span></span><br><span class="line">        <span class="keyword">case</span> .linguine: <span class="keyword">return</span> <span class="string">"Linguine"</span></span><br><span class="line">        <span class="keyword">case</span> .tagliatelle: <span class="keyword">return</span> <span class="string">"Tagliatelle"</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> shape: <span class="type">String</span> &#123;</span><br><span class="line">        <span class="keyword">switch</span> <span class="keyword">self</span> &#123;</span><br><span class="line">        <span class="keyword">case</span> .conchiglie: <span class="keyword">return</span> <span class="string">"Shells"</span></span><br><span class="line">        <span class="keyword">case</span> .fusilli: <span class="keyword">return</span> <span class="string">"Twists"</span></span><br><span class="line">        <span class="keyword">case</span> .linguine: <span class="keyword">return</span> <span class="string">"Long and skinny"</span></span><br><span class="line">        <span class="keyword">case</span> .tagliatelle: <span class="keyword">return</span> <span class="string">"Long ribbons"</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> image: <span class="type">UIImage</span> &#123;</span><br><span class="line">        <span class="keyword">switch</span> <span class="keyword">self</span> &#123;</span><br><span class="line">        <span class="keyword">case</span> .conchiglie: <span class="keyword">return</span> <span class="type">UIImage</span>(named: <span class="string">"conchiglie"</span>)!</span><br><span class="line">        <span class="keyword">case</span> .fusilli: <span class="keyword">return</span> <span class="type">UIImage</span>(named: <span class="string">"fusilli"</span>)!</span><br><span class="line">        <span class="keyword">case</span> .linguine: <span class="keyword">return</span> <span class="type">UIImage</span>(named: <span class="string">"linguine"</span>)!</span><br><span class="line">        <span class="keyword">case</span> .tagliatelle: <span class="keyword">return</span> <span class="type">UIImage</span>(named: <span class="string">"tagliatelle"</span>)!</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Generate data for the table view</span></span><br><span class="line"><span class="keyword">var</span> objectsForTableView: [<span class="type">Pasta</span>] = <span class="type">Pasta</span>.allcases</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>Here is the pasta table:<br><div class="figure center" style="width:;"><a class="fancybox" href="pasta-table.jpg" title data-caption data-fancybox="default"><img class="fig-img" src="pasta-table.jpg" alt></a></div></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;The new CaseIterable protocol gives your Enum new ability to generate an array of all cases in an enum.&lt;/p&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="Swift" scheme="https://jasonhan1990.github.io/tags/Swift/"/>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
  </entry>
  
  <entry>
    <title>AVCapturePhotoSettings Reuse Error</title>
    <link href="https://jasonhan1990.github.io/2018/10/16/error-record-2/"/>
    <id>https://jasonhan1990.github.io/2018/10/16/error-record-2/</id>
    <published>2018-10-17T03:15:54.000Z</published>
    <updated>2018-10-18T03:17:29.000Z</updated>
    
    <content type="html"><![CDATA[<p>The error message when you reused an AVCapturePhotoSettings object is <code>-[AVCapturePhotoOutput capturePhotoWithSettings:delegate:] Settings may not be re-used&#39;</code>.</p><a id="more"></a><p>From apple’s documents.</p><blockquote><h3 id="Important"><a href="#Important" class="headerlink" title="Important"></a>Important</h3><p>It is illegal to reuse a AVCapturePhotoSettings instance for multiple captures. Calling the capturePhoto(with:delegate:) method throws an exception (invalidArgumentException) if the settings object’s uniqueID value matches that of any previously used settings object.<br>To reuse a specific combination of settings, use the init(from:) initializer to create a new, unique AVCapturePhotoSettings instance from an existing photo settings object.</p></blockquote><p>The correct way to do it is to make a new AVCapturePhotoSettings object from copying your pre-made object:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">AVCapturePhotoSettings</span> *uniqueSetting = [<span class="built_in">AVCapturePhotoSettings</span> photoSettingsFromPhotoSettings:<span class="keyword">self</span>.outputSettings];</span><br><span class="line">[<span class="keyword">self</span>.imageOutput capturePhotoWithSettings:uniqueSetting delegate:<span class="keyword">self</span>];</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;The error message when you reused an AVCapturePhotoSettings object is &lt;code&gt;-[AVCapturePhotoOutput capturePhotoWithSettings:delegate:] Settings may not be re-used&amp;#39;&lt;/code&gt;.&lt;/p&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="AVFoundation" scheme="https://jasonhan1990.github.io/tags/AVFoundation/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="Error" scheme="https://jasonhan1990.github.io/tags/Error/"/>
    
  </entry>
  
  <entry>
    <title>Blog moving notice</title>
    <link href="https://jasonhan1990.github.io/2018/09/17/blog-moving-notice/"/>
    <id>https://jasonhan1990.github.io/2018/09/17/blog-moving-notice/</id>
    <published>2018-09-18T02:36:10.000Z</published>
    <updated>2018-09-25T02:36:17.000Z</updated>
    
    <content type="html"><![CDATA[<p>I am starting to move my previous blog and project page from Squrespace to Github page starting today. All posts will keep the same publishing date as before. After finishing moving, I will link my personal domain <a href="http://www.junchenghan.com" target="_blank" rel="noopener">www.junchenghan.com</a> to this Github page.</p><p>Thanks.</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;I am starting to move my previous blog and project page from Squrespace to Github page starting today. All posts will keep the same publi
      
    
    </summary>
    
      <category term="Other" scheme="https://jasonhan1990.github.io/categories/Other/"/>
    
    
      <category term="Other" scheme="https://jasonhan1990.github.io/tags/Other/"/>
    
  </entry>
  
  <entry>
    <title>《iOS面试之道》阅读笔记（3）</title>
    <link href="https://jasonhan1990.github.io/2018/08/29/ios-%E9%9D%A2%E8%AF%95%E4%B9%8B%E9%81%93-3/"/>
    <id>https://jasonhan1990.github.io/2018/08/29/ios-面试之道-3/</id>
    <published>2018-08-30T02:45:36.000Z</published>
    <updated>2018-10-04T19:37:06.000Z</updated>
    
    <content type="html"><![CDATA[<p>直接跳到Swift语言吧。Swift很快很安全，而且就我的感受来说，写Swift有一种写脚本语言的快感。但是Swift还有很多路要走，现在最感到头疼的就是和ObjC的混编吧。</p><a id="more"></a><h1 id="Swift"><a href="#Swift" class="headerlink" title="Swift"></a>Swift</h1><p>我在这里就按照书中的顺序来做个笔记和添加我所知道的更多知识。</p><h2 id="Class和Struct和Enum"><a href="#Class和Struct和Enum" class="headerlink" title="Class和Struct和Enum"></a>Class和Struct和Enum</h2><p>对于Class和Struct，一个是引用类型，一个是值类型我就不赘述了，书里写的很清楚。</p><h3 id="先说说Struct："><a href="#先说说Struct：" class="headerlink" title="先说说Struct："></a>先说说Struct：</h3><p>默认下Struct内部的函数是不能修改Struct内部的属性（properties）的，但是我们可以在<code>func</code>前面加<code>mutating</code>关键字来打破默认。例如下面的doSomethingToInternalProperties()。</p><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">TV</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> height: <span class="type">Float</span></span><br><span class="line">    <span class="keyword">var</span> width: <span class="type">Float</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">var</span> <span class="type">Tag</span> = <span class="string">"electronics"</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> diagonals: <span class="type">Int</span> &#123;</span><br><span class="line">      <span class="comment">// calculated here</span></span><br><span class="line">      <span class="keyword">return</span> result</span><br><span class="line">    &#125;</span><br><span class="line">  </span><br><span class="line">    <span class="keyword">var</span> spaceTaken: <span class="type">Double</span> &#123;</span><br><span class="line">      <span class="keyword">get</span> &#123;</span><br><span class="line">        <span class="comment">// calculate here</span></span><br><span class="line">        <span class="keyword">return</span> result</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">set</span> &#123;</span><br><span class="line">        height = <span class="type">Double</span>(newValue)</span><br><span class="line">      &#125;  </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">doSomethingToInternalProperties</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="comment">// do something</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>更多：</p><p>上面的例子里一共有三种不同的属性（properties）。</p><ul><li>height和width是实例属性（instance properties）。这种属性存储了关于一个实例的信息，如高和宽的具体数值。</li><li>diagonals是计算属性（Computed Propertie）。这种属性其实根本就不存储任何值，它只是提供了一个getter或者setter让你直接获取一些计算后的值或直接修改实例属性。</li><li>Tags是类属性，开头要用<code>static</code>关键字。即不需要创建实例就能获得的关于这个类的属性。<code>let tvTag = TV.Tag</code></li></ul><h3 id="然后Enum："><a href="#然后Enum：" class="headerlink" title="然后Enum："></a>然后Enum：</h3><p>个人感觉Swift的Enum真的很强大啊，可以有不同的case，也可以有func。Enum和Struct很相似，就不赘述了。我们体验Enum的强大吧，下面是用Enum做一个数学表达式，然后用Enum内部的函数来求值。</p><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// example</span></span><br><span class="line"><span class="keyword">indirect</span> <span class="class"><span class="keyword">enum</span> <span class="title">Expression</span> </span>&#123;</span><br><span class="line">  <span class="keyword">case</span> number(<span class="type">Int</span>)</span><br><span class="line">  <span class="keyword">case</span> add(<span class="type">Expression</span>, <span class="type">Expression</span>)</span><br><span class="line">  </span><br><span class="line">  <span class="function"><span class="keyword">func</span> <span class="title">evaluate</span><span class="params">()</span></span> -&gt; <span class="type">Int</span> &#123;</span><br><span class="line">    <span class="keyword">switch</span> <span class="keyword">self</span> &#123;</span><br><span class="line">    <span class="keyword">case</span> <span class="keyword">let</span> .number(value):</span><br><span class="line">      <span class="keyword">return</span> value</span><br><span class="line">    <span class="keyword">case</span> <span class="keyword">let</span> .add(<span class="keyword">left</span>, <span class="keyword">right</span>):</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">left</span>.evaluate() + <span class="keyword">right</span>.evaluate()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> first = <span class="type">Expression</span>.number(<span class="number">50</span>)</span><br><span class="line"><span class="keyword">var</span> second = <span class="type">Expression</span>.number(<span class="number">12</span>)</span><br><span class="line"><span class="keyword">var</span> sum = <span class="type">Expression</span>.add(first, second)</span><br><span class="line">second.evaluate() <span class="comment">// 12</span></span><br><span class="line">first.evaluate() <span class="comment">// 50</span></span><br><span class="line">sum.evaluate() <span class="comment">// 62</span></span><br></pre></td></tr></table></figure><p>解释一下，这里定义了一个数学表达式Expression的Enum。数学表达式有很多很多中，这里我写了：</p><ol><li>代表一个整数的表达式number(Int)</li><li>和加法表达式add(Expression, Expression)，之所以括号里面的类型是Expression，是因为它不仅可能是两个整数相加，也可能是两个相加的表达式在求和，类似于（1 + 2）+ 3。</li></ol><p>然后内部有一个求值的方程，他会判断，如果这个表达式是一个整数表达式，那么就返回整数的值，如果是加法表达式，这里用到递归，左边表达式求值后再加上右边表达式的值。</p><p>你看的没错，Enum里面可以用递归嵌套。这是因为有递归嵌套，所以Enum前面需要加上<code>indirect</code>关键字。</p><h3 id="最后Class："><a href="#最后Class：" class="headerlink" title="最后Class："></a>最后Class：</h3><p>对比与Struct的区别，一个是传递的值得类型不同，另一个是Struct中的属性（properties）是可以不初始化的，就像上面的列子里，height和width我都没有初始化，甚至这两个属性我都没有定义为optional。</p><p>但是Class中的属性是要定义的，如果你不定义，那么你多半会得到Class ‘XXX’ has no initializers这样的错误警告。例子：</p><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Compiler error: Class 'Address' has no initializers</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Address</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> street: <span class="type">String</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// you can solve by these ways</span></span><br><span class="line"><span class="comment">// add a init function</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Address</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> street: <span class="type">String</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">init</span>(street: <span class="type">String</span>) &#123;</span><br><span class="line">      <span class="keyword">self</span>.street = street</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// init the street by default</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Address</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> street: <span class="type">String</span> = <span class="string">""</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// set street to optional</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Address</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> street: <span class="type">String</span>?</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="更多："><a href="#更多：" class="headerlink" title="更多："></a>更多：</h3><p>Class作为对象当然是可以继承的。一个类继承另一个类后，可以覆盖（override）它父类func的实现方法。如果你不希望子类获得这样的能力，你可以在父类的func前面加上<code>final</code>关键字。Swift不允许类的多继承。</p><p>在Swift里面，比较推荐用protocal来代替继承，因为继承会增加程序见的耦合度，增加程序出错的可能性。用protocal的话，就是底耦合度，protocal类似于Java的interface，protocal提供所需的属性和方法，但不实现他们。这些属性和方法由遵循（comfirm）该协议的类来实现。</p><p>我看书的目录有关于面向协议的编程一节，这里就不多说了，看到那一节在说。</p><h2 id="Optional："><a href="#Optional：" class="headerlink" title="Optional："></a>Optional：</h2><p>简单理解，就是定义一个value能不能是空的（nil）。一般用if let else或是guard let else来判断。</p><p>用guard比if let的好处在于，可以减少if else的嵌套。</p><h2 id="Protocol协议："><a href="#Protocol协议：" class="headerlink" title="Protocol协议："></a>Protocol协议：</h2><p>Swift中的协议真的用法很灵活，大家做好多看看官方Swift教科书。这里列出一些：</p><ul><li>Class，Struct，Enum都可以遵循Protocal。你也可以通过在<code>protocal</code>前面加<code>@objc</code>或是在<code>protocal</code>后加<code>class</code>来强制只有Class能用这个Protocal</li></ul><figure class="highlight swift"><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"><span class="meta">@objc</span> <span class="class"><span class="keyword">protocol</span> <span class="title">SomeProtocal</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 或者</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">protocol</span> <span class="title">SomeProtocal</span>: <span class="title">class</span> </span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>protocal可以定义特定的初始化方法。Class在实现这类初始化方法时，前面要加<code>require</code>。</li></ul><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">protocol</span> <span class="title">SomeProtocal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> aVar: <span class="type">Int</span> &#123; <span class="keyword">get</span> <span class="keyword">set</span> &#125;</span><br><span class="line">    <span class="keyword">init</span>()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SomeClass</span>: <span class="title">SomeProtocal</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> aVar: <span class="type">Int</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">required</span> <span class="keyword">init</span>() &#123;</span><br><span class="line">        aVar = <span class="number">7</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">init</span>(<span class="number">_</span> aVar: <span class="type">Int</span>) &#123;</span><br><span class="line">        <span class="keyword">self</span>.aVar = aVar</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">SomeStruct</span>: <span class="title">SomeProtocal</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> aVar: <span class="type">Int</span></span><br><span class="line">    <span class="keyword">init</span>() &#123;</span><br><span class="line">        aVar = <span class="number">7</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>protocal可以作为一个类来成为（protocal as type）：<ul><li>一个方程的返回值类型</li><li>一个值和属性的类型</li><li>数组，字典或者其他容器中存储值得类型</li></ul></li></ul><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">protocol</span> <span class="title">Vehicle</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Car</span>: <span class="title">Vehicle</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Bike</span>: <span class="title">Vehicle</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> car = <span class="type">Car</span>(), bike = <span class="type">Bike</span>()</span><br><span class="line"><span class="keyword">var</span> vehicles : [<span class="type">Vehicle</span>] = [car, bike]</span><br><span class="line"></span><br><span class="line"><span class="comment">// 更多：类型判定</span></span><br><span class="line">vehicles.forEach &#123; v <span class="keyword">in</span></span><br><span class="line">    <span class="keyword">if</span> v <span class="keyword">is</span> <span class="type">Car</span> &#123;</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">"I'm a car"</span>)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> v <span class="keyword">is</span> <span class="type">Bike</span> &#123;</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">"I'm a bike"</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>一个class或struct可以继承多个协议。</li><li>默认下，继承协议的class和struct必须实现协议中的所有属性和方法。但是可以通过转化Swift协议到ObjC协议来增加optional。</li></ul><figure class="highlight swift"><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"><span class="meta">@objc</span> <span class="class"><span class="keyword">protocol</span> <span class="title">SomeProtocal</span> </span>&#123;</span><br><span class="line">    <span class="meta">@objc</span> <span class="keyword">optional</span> <span class="function"><span class="keyword">func</span> <span class="title">someMethod</span><span class="params">()</span></span> -&gt; <span class="type">Int</span></span><br><span class="line">    <span class="meta">@objc</span> <span class="keyword">optional</span> <span class="keyword">var</span> someProperty: <span class="type">Int</span> &#123; <span class="keyword">get</span> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>代理（Delegation）不是协议（Protocal），它是iOS中的一种设计模式，但是依赖于协议这个技术。用代理的好处在于，委托方不会知道代理方的任何内部情况，通过协议，委托方制定代理方需要实现的功能，然后委托方按照协议实现功能就好了。代理是可以传递消息的，它也是iOS种的一种消息传递方式（其他有：通知NSNotification，Block或Closure，target action，KVO）。</li></ul><h2 id="泛型Generic："><a href="#泛型Generic：" class="headerlink" title="泛型Generic："></a>泛型Generic：</h2><p>书里面简单介绍的Swift泛型怎么用。在实际运用的时候，我们也可以限制泛型值的类型。看个例子，下面的方程返回泛型数组中一个特定值的下标。</p><figure class="highlight swift"><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"><span class="function"><span class="keyword">func</span> <span class="title">findIndex</span>&lt;T&gt;<span class="params">(of valueToFind: T, <span class="keyword">in</span> array:[T])</span></span> -&gt; <span class="type">Int</span>? &#123;</span><br><span class="line">    <span class="keyword">for</span> (index, value) <span class="keyword">in</span> array.enumerated() &#123;</span><br><span class="line">        <span class="keyword">if</span> value == valueToFind &#123;</span><br><span class="line">            <span class="keyword">return</span> index</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这段程序是有问题的，因为不是所有类型的值都能使用<code>==</code>来判断相等，特别是工程师自己写的类。只有满足实现了Equatable协议的Class和Struct，程序才能正常运行。所以我们可以对泛型T做限制。</p><figure class="highlight swift"><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"><span class="function"><span class="keyword">func</span> <span class="title">findIndex</span>&lt;T: Equatable&gt;<span class="params">(of valueToFind: T, <span class="keyword">in</span> array:[T])</span></span> -&gt; <span class="type">Int</span>? &#123;</span><br><span class="line">    <span class="comment">// same as above</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 或者用where关键字</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">findIndex</span>&lt;T&gt;<span class="params">(of valueToFind: T, <span class="keyword">in</span> array:[T])</span></span> -&gt; <span class="type">Int</span>? <span class="keyword">where</span> <span class="type">T</span>: <span class="type">Equatable</span> &#123;</span><br><span class="line">    <span class="comment">// same as above</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="Open-vs-Public"><a href="#Open-vs-Public" class="headerlink" title="Open vs. Public"></a>Open vs. Public</h2><p><strong>open </strong></p><ul><li>open 修饰的 class 在 Module 内部和外部都可以被访问和继承</li><li>open 修饰的 func 在 Module 内部和外部都可以被访问和重载（override)</li></ul><p><strong>public </strong></p><ul><li>public 修饰的 class 在 Module 内部可以访问和继承，在外部只能访问</li><li>public 修饰的 func 在 Module 内部可以被访问和重载（override）,在外部只能访问</li></ul><h2 id="Copy-on-write"><a href="#Copy-on-write" class="headerlink" title="Copy-on-write"></a>Copy-on-write</h2><p>Swift将很多ObjC中的数据类型从引用类（reference type）改成了值类（value type）。这样及降低了内存泄露的风险，也提高了内存效率。书中给了一个例子：</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// arrayA 是一个数组，为值类型</span></span><br><span class="line"><span class="keyword">let</span> arrayA = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line"><span class="comment">// arrayB 这个时候与 arrayA 在内存中是同一个东西，内存中并没有生成新的数组</span></span><br><span class="line"><span class="keyword">let</span> arrayB = arrayA</span><br><span class="line"><span class="comment">// arrayB 被修改了，此时 arrayB 在内存中变成了一个新的数组，而不是原来的 arrayA</span></span><br><span class="line">arrayB.append(<span class="number">4</span>)</span><br></pre></td></tr></table></figure><p>然后说到，当arrayB没有改变的时候，arrayB和arrayA指向同一个内存。意思就是他们应该有相同的address。</p><p>然后我就像去证明一下，首先通过看官方文献我找到了这样一个方程来返回地址<code>withUnsafePointer(to:_:)。</code></p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> array1: [<span class="type">Int</span>] = [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line"><span class="keyword">var</span> array2 = array1</span><br><span class="line"></span><br><span class="line"><span class="built_in">withUnsafePointer</span>(to: &amp;array1) &#123;</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">" 1 has address: <span class="subst">\($<span class="number">0</span>)</span>"</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">withUnsafePointer</span>(to: &amp;array2) &#123;</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">" 2 has address: <span class="subst">\($<span class="number">0</span>)</span>"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出：</span></span><br><span class="line"><span class="comment">// 1 has address: 0x000000011aabf4d0</span></span><br><span class="line"><span class="comment">// 2 has address: 0x000000011aabf4d8</span></span><br></pre></td></tr></table></figure><p>结果输出地址不一样，我当时就很怀疑人生，然后翻看一些书籍和别人的博客寻求答案。我看到的各种东西都证明《iOS面试之道》里是正确的，但是证明呢？</p><p>接着我看到了这个方法，用<code>UnsafeRawPointer</code>。</p><figure class="highlight swift"><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 class="function"><span class="keyword">func</span> <span class="title">print</span><span class="params">(address o: UnsafeRawPointer )</span></span> &#123;</span><br><span class="line">    <span class="built_in">print</span>(<span class="type">String</span>(format: <span class="string">"%p"</span>, <span class="type">Int</span>(bitPattern: o)))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> array1: [<span class="type">Int</span>] = [<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line"><span class="keyword">var</span> array2 = array1</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(address: array1) <span class="comment">//0x60c00006f4a0</span></span><br><span class="line"><span class="built_in">print</span>(address: array2) <span class="comment">//0x60c00006f4a0</span></span><br></pre></td></tr></table></figure><p>终于得到了相同的地址。那么UnsafeRawPointer和UnsafePointer的区别是什么，我的理解是，UnsafeRawPointer是指向没有类型（untyped）的数据，可以理解为存在内存中裸的数据，例子中就是0在内存中所在位置，而UnsafePointer是指向有类型（typed）的数据，例子中应该是指向我们建立的Array在内存中的地址。</p><h2 id="static-methods-vs-class-methods"><a href="#static-methods-vs-class-methods" class="headerlink" title="static methods vs. class methods"></a>static methods vs. class methods</h2><ul><li>static 和 class都是用来指定类方法</li><li>class关键字指定的类方法 可以被 override</li><li>static关键字指定的类方法 不能被 override</li></ul><h2 id="as-vs-as"><a href="#as-vs-as" class="headerlink" title="as? vs. as!"></a>as? vs. as!</h2><p>这个属于Swift的类型转换（type cast）。</p><ul><li>as? - 表示这个类型转换过程是optional的。被赋予的值肯定是一个optional的值。如果类型转换失败，返回nil。</li><li>as! - 表示这个类型转换过程不是optional的. System will crash if down casting fails.如果类型转换失败，程序崩溃。</li></ul><p>加了些我知道的，但是书里没有提及的知识，先这么多吧，我以前的笔记挺乱的，整理好了有什么要加的在加进来。</p><p>Reference：<br><a href="https://xiaozhuanlan.com/ios-interview" target="_blank" rel="noopener">https://xiaozhuanlan.com/ios-interview</a> 故胤道长和唐巧两位大神的书《iOS 面试之道》<br><a href="https://swiftdoc.org/" target="_blank" rel="noopener">https://swiftdoc.org/</a><br><a href="https://developer.apple.com/documentation/swift/unsaferawpointer" target="_blank" rel="noopener">https://developer.apple.com/documentation/swift/unsaferawpointer</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;直接跳到Swift语言吧。Swift很快很安全，而且就我的感受来说，写Swift有一种写脚本语言的快感。但是Swift还有很多路要走，现在最感到头疼的就是和ObjC的混编吧。&lt;/p&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="Swift" scheme="https://jasonhan1990.github.io/tags/Swift/"/>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="读书笔记" scheme="https://jasonhan1990.github.io/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
      <category term="iOS面试" scheme="https://jasonhan1990.github.io/tags/iOS%E9%9D%A2%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>《iOS面试之道》阅读笔记（2）</title>
    <link href="https://jasonhan1990.github.io/2018/08/28/ios-%E9%9D%A2%E8%AF%95%E4%B9%8B%E9%81%93-2/"/>
    <id>https://jasonhan1990.github.io/2018/08/28/ios-面试之道-2/</id>
    <published>2018-08-29T02:16:24.000Z</published>
    <updated>2019-03-04T23:42:45.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="更多数据结构"><a href="#更多数据结构" class="headerlink" title="更多数据结构"></a>更多数据结构</h2><a id="more"></a><h3 id="链表"><a href="#链表" class="headerlink" title="链表"></a>链表</h3><p>单向链表节点：</p><figure class="highlight swift"><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 class="class"><span class="keyword">class</span> <span class="title">ListNode</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> val: <span class="type">Int</span></span><br><span class="line">    <span class="keyword">var</span> next: <span class="type">ListNode</span>?</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">init</span>(<span class="number">_</span> val: <span class="type">Int</span>) &#123;</span><br><span class="line">        <span class="keyword">self</span>.val = val</span><br><span class="line">        <span class="keyword">self</span>.next = <span class="literal">nil</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>双向的话就多加一个prev。</p><p>解决链表问题是常用的技巧：</p><ol><li>dummy head: 创建一个辅助的链表头结点，然后返回的时候为return dummy.next. 这个技巧为了省去我们判断头结点是否为nil，减少程序错误。</li><li>fast and slow pointer：快慢指针，慢指针每次移动一步，快指针每次移动两步。用快慢指针可以轻松获取链表中间节点，和判断链表是否有环。</li></ol><h2 id="栈和队列"><a href="#栈和队列" class="headerlink" title="栈和队列"></a>栈和队列</h2><p>栈Stack，后进先出（LIFO）。Swift没有现成的Stack，但是可以用Array来轻松实现。</p><p>在iOS面试之道里面，所有不同数据类型的Stack的创建是遵循一个Stack Protocol，然后用Associated Types<br>来设定不同的数据类型。这非常Swifty。这里也可以用Swift自带的Generic来做：</p><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Stack</span>&lt;<span class="title">Element</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> store = [<span class="type">Element</span>]()</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> size: <span class="type">Int</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> store.<span class="built_in">count</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> peek: <span class="type">Element</span>? &#123;</span><br><span class="line">        <span class="keyword">return</span> store.last</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">push</span><span class="params">(<span class="number">_</span> item: Element)</span></span> &#123;</span><br><span class="line">        store.append(item)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">pop</span><span class="params">()</span></span> &#123;</span><br><span class="line">        store.removeLast()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> intStack = <span class="type">Stack</span>&lt;<span class="type">Int</span>&gt;()</span><br><span class="line">intStack.push(<span class="number">1</span>)</span><br></pre></td></tr></table></figure><p>队列Queue，先进先出（FIFO）。同样也可以用Array来实现。</p><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Queue</span>&lt;<span class="title">Element</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> store = [<span class="type">Element</span>]()</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> size: <span class="type">Int</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> store.<span class="built_in">count</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> isEmpty: <span class="type">Bool</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> store.<span class="built_in">count</span> == <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">enqueue</span><span class="params">(<span class="number">_</span> e: Element)</span></span> &#123;</span><br><span class="line">        store.append(e)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">dequeue</span><span class="params">()</span></span> -&gt; <span class="type">Element</span>? &#123;</span><br><span class="line">        <span class="keyword">return</span> store.first</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> queue = <span class="type">Queue</span>&lt;<span class="type">Int</span>&gt;()</span><br></pre></td></tr></table></figure><p>简单解释用两个Stack实现一个Queue。假设我们有StackA和StackB，StackA用来存Enqueue进来的元素，StackB用来处理Dequeue的元素。</p><ul><li>Enqueue：直接把新的元素放进StackA</li><li>Dequeue：<ol><li>如果StackB是空的，则把StackA中的所有元素dequeue出来然后enqueue进StackB中，这个时候，之前最先进去StackA的元素就到了StackB的顶部，然后就只需要dequeue出StackB里的一个元素返回。</li><li>如果StackB中不是空，就直接dequeue然后返回。</li></ol></li></ul><p>用两个Queue实现Stack要稍微难想一点点，要点事两个Queue要shift他们的功能。</p><p><strong>更多：</strong></p><p><strong>如何实现一个线程安全的Stack</strong>。实现线程安全在iOS中有多种方法，主要分为运用锁（lock）相关的技术和运用线程先关的技术。在阅读苹果关于多线程编程的文档后，可以得知，苹果官方推荐工程师用线程相关的技术，特别是GCD，来做线程安全。原因是因为：iOS系统分为应用层（application level）和内核层（kernel level）。锁的处理是在内核层，当程序每一次创建锁和开锁的时候，它都要从应用层转到内核层进行操作，这个过程的消耗是巨大的，更不用说在用锁实现线程安全的时候会有大量的建锁和开锁的程序。而苹果的GCD则不同，它基本上是只运行在应用层的，只有真正有需要的时候，才会进去内核层。</p><p>再来说说CGD做线层安全，我所知道的有两个方法：</p><ol><li>用串行队列（Serial dispatch queue）的方法</li><li>用并行队列（Concurrent dispatch queue）+ 栅栏（Barrier）的方法</li></ol><p>我以前一直认为第二种方法更高效，毕竟是并发嘛。但是在和一个苹果工程师交谈后和阅读苹果文档后，我发现了问题所在。在用第二种方法的时候，程序会创建Barrier和删除Barrier，情形类似于锁，这个过程会消耗很多性能。如果这个线程安全的Stack有大量的数据操作的话，自然就慢了。</p><p>看了这么多，其实苹果官方文档中有这个一句话：</p><p><strong>Serial dispatch queue offer a more efficient alternative to locks and other synchronization primitives.</strong></p><p>意思就是串行最棒棒。所以我为什么之前要讲这么多。</p><p>给个例子吧，这个是我以前写的Thread Safe Stack，虽然是用ObjC，但是可以看看。这里我是用LinkList来实现Stack。所有的程序都是ObjC，不过更优秀的做法是用C或C++来写LinkList。</p><p><code>ListNode.h</code></p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#import <span class="meta-string">&lt;Foundation/Foundation.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">ListNode</span> : <span class="title">NSObject</span> &lt;<span class="title">NSSecureCoding</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">strong</span>, <span class="keyword">nullable</span>) <span class="keyword">id</span> value;</span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">strong</span>, <span class="keyword">nullable</span>) ListNode *next;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">nullable</span> <span class="keyword">instancetype</span>)initWithValue:(<span class="keyword">nullable</span> <span class="keyword">id</span>)value andNext:(<span class="keyword">nullable</span> ListNode *)next;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure><p><code>ListNode.m</code></p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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"><span class="meta">#import <span class="meta-string">"ListNode.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">ListNode</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">instancetype</span>)init</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">self</span> = [<span class="keyword">super</span> init];</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">self</span>) &#123;</span><br><span class="line">        <span class="keyword">self</span>.next = <span class="literal">NULL</span>;</span><br><span class="line">        <span class="keyword">self</span>.value = <span class="literal">NULL</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">self</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">instancetype</span>)initWithValue:(<span class="keyword">id</span>)value andNext:(ListNode *)next &#123;</span><br><span class="line">    <span class="keyword">self</span> = [<span class="keyword">super</span> init];</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">self</span>) &#123;</span><br><span class="line">        <span class="keyword">self</span>.next = next;</span><br><span class="line">        <span class="keyword">self</span>.value = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">self</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#pragma mark - NSCoding</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#define kValueKey @<span class="meta-string">"valueKey"</span></span></span><br><span class="line"><span class="meta">#define kNextKey @<span class="meta-string">"nextKey"</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)encodeWithCoder:(<span class="keyword">nonnull</span> <span class="built_in">NSCoder</span> *)aCoder &#123;</span><br><span class="line">    [aCoder encodeObject:_value forKey:kValueKey];</span><br><span class="line">    [aCoder encodeObject:_next forKey:kNextKey];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">nullable</span> <span class="keyword">instancetype</span>)initWithCoder:(<span class="keyword">nonnull</span> <span class="built_in">NSCoder</span> *)aDecoder &#123;</span><br><span class="line">    <span class="keyword">id</span> value = [aDecoder decodeObjectForKey:kValueKey];</span><br><span class="line">    <span class="keyword">id</span> next = [aDecoder decodeObjectOfClass:[ListNode <span class="keyword">class</span>] forKey:kNextKey];</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">self</span> = [<span class="keyword">super</span> init];</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">self</span>) &#123;</span><br><span class="line">        <span class="keyword">self</span>.value = value;</span><br><span class="line">        <span class="keyword">self</span>.next = next;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">self</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">+ (<span class="built_in">BOOL</span>)supportsSecureCoding &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">YES</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure><p><code>ThreadSafeStack.h</code></p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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"><span class="meta">#import <span class="meta-string">&lt;Foundation/Foundation.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@protocol</span> <span class="title">ThreadSafeStackProtocol</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@end</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">ThreadSafeStack</span>&lt;<span class="title">__covariant</span> <span class="title">ObjectType</span>&gt; : <span class="title">NSObject</span> &lt;<span class="title">NSSecureCoding</span>, <span class="title">NSMutableCopying</span>, <span class="title">NSCopying</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// MARK: initializer</span></span><br><span class="line">- (<span class="keyword">instancetype</span>)init;</span><br><span class="line"></span><br><span class="line"><span class="comment">// MARK: public motheds</span></span><br><span class="line">- (<span class="keyword">void</span>)push:(ObjectType)object;</span><br><span class="line">- (ObjectType)pop;</span><br><span class="line">- (ObjectType)peek;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">weak</span>) <span class="keyword">id</span>&lt;ThreadSafeStackProtocol&gt; delegate;</span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">strong</span>) <span class="built_in">NSArray</span>&lt;<span class="keyword">id</span>&lt;ThreadSafeStackProtocol&gt;&gt; * array;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">readonly</span>) <span class="built_in">NSUInteger</span> count;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure><p><code>ThreadSafeStack.m</code></p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#import <span class="meta-string">"ThreadSafeStack.h"</span></span></span><br><span class="line"><span class="meta">#import <span class="meta-string">"ListNode.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">ThreadSafeStack</span>()</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">strong</span>) ListNode *head;</span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">strong</span>) <span class="built_in">dispatch_queue_t</span> isolationQueue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@end</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">ThreadSafeStack</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">instancetype</span>)init &#123;</span><br><span class="line">    <span class="keyword">self</span> = [<span class="keyword">super</span> init];</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">self</span>) &#123;</span><br><span class="line">        _head = <span class="literal">NULL</span>;</span><br><span class="line">        <span class="built_in">NSString</span> *name = [<span class="built_in">NSString</span> stringWithFormat:<span class="string">@"com.ThreadSafeStack.dispatchQueue.%@"</span>, [[<span class="built_in">NSUUID</span> UUID] UUIDString]];</span><br><span class="line">        _isolationQueue = dispatch_queue_create([name cStringUsingEncoding:<span class="built_in">NSASCIIStringEncoding</span>], DISPATCH_QUEUE_SERIAL);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">self</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#pragma mark - setter and getter</span></span><br><span class="line"></span><br><span class="line">- (<span class="built_in">NSUInteger</span>)count &#123;</span><br><span class="line">    __block <span class="built_in">NSInteger</span> res = <span class="number">0</span>;</span><br><span class="line">    <span class="built_in">dispatch_sync</span>(<span class="keyword">self</span>.isolationQueue, ^&#123;</span><br><span class="line">        ListNode *temp = <span class="keyword">self</span>.head;</span><br><span class="line">        <span class="keyword">while</span> (temp != <span class="literal">NULL</span>) &#123;</span><br><span class="line">            res += <span class="number">1</span>;</span><br><span class="line">            temp = temp.next;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#pragma mark - public methods</span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">id</span>)peek &#123;</span><br><span class="line">    __block <span class="keyword">id</span> res;</span><br><span class="line">    <span class="built_in">dispatch_sync</span>(<span class="keyword">self</span>.isolationQueue, ^&#123;</span><br><span class="line">        res = <span class="keyword">self</span>.head.value;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">id</span>)pop &#123;</span><br><span class="line">    __block <span class="keyword">id</span> res = <span class="literal">NULL</span>;</span><br><span class="line">    <span class="built_in">dispatch_sync</span>(<span class="keyword">self</span>.isolationQueue, ^&#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">self</span>.head == <span class="literal">NULL</span>) &#123;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            res = <span class="keyword">self</span>.head.value;</span><br><span class="line">            <span class="keyword">self</span>.head = <span class="keyword">self</span>.head.next;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)push:(<span class="keyword">id</span>)object &#123;</span><br><span class="line">    <span class="built_in">dispatch_async</span>(<span class="keyword">self</span>.isolationQueue, ^&#123;</span><br><span class="line">        <span class="keyword">self</span>.head = [[ListNode alloc] initWithValue:object andNext:<span class="keyword">self</span>.head];</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#pragma mark - override methods</span></span><br><span class="line"></span><br><span class="line">- (<span class="built_in">NSString</span> *)description &#123;</span><br><span class="line">    <span class="built_in">NSMutableString</span> *des = [<span class="built_in">NSMutableString</span> stringWithFormat:<span class="string">@"%@: "</span>, [<span class="keyword">super</span> description]];</span><br><span class="line">    <span class="built_in">dispatch_sync</span>(<span class="keyword">self</span>.isolationQueue, ^&#123;</span><br><span class="line">        ListNode *temp = <span class="keyword">self</span>.head;</span><br><span class="line">        <span class="keyword">while</span> (temp != <span class="literal">NULL</span>) &#123;</span><br><span class="line">            [des appendString:[<span class="built_in">NSString</span> stringWithFormat:<span class="string">@"%@ "</span>, [temp.value description]]];</span><br><span class="line">            temp = temp.next;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">return</span> [des <span class="keyword">copy</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#pragma mark - NSCopy and NSMutableCopy</span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">id</span>&lt;<span class="built_in">NSCopying</span>, <span class="built_in">NSSecureCoding</span>&gt;)copyWithZone:(<span class="built_in">NSZone</span> *)zone &#123;</span><br><span class="line">    ThreadSafeStack *<span class="keyword">copy</span> = [[[<span class="keyword">self</span> <span class="keyword">class</span>] allocWithZone:zone] init];</span><br><span class="line">    <span class="keyword">copy</span>.head = <span class="keyword">self</span>.head;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">copy</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">id</span>)mutableCopyWithZone:(<span class="built_in">NSZone</span> *)zone &#123;</span><br><span class="line">    <span class="keyword">return</span> [<span class="keyword">self</span> copyWithZone:zone];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">#pragma mark - NSCoding</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#define kHeadKey @<span class="meta-string">"headKey"</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)encodeWithCoder:(<span class="keyword">nonnull</span> <span class="built_in">NSCoder</span> *)aCoder &#123;</span><br><span class="line">    [aCoder encodeObject:_head forKey:kHeadKey];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">nullable</span> <span class="keyword">instancetype</span>)initWithCoder:(<span class="keyword">nonnull</span> <span class="built_in">NSCoder</span> *)aDecoder &#123;</span><br><span class="line">    <span class="keyword">id</span> head = [aDecoder decodeObjectOfClass:[ListNode <span class="keyword">class</span>] forKey:kHeadKey];</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">self</span> = [<span class="keyword">super</span> init];</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">self</span>) &#123;</span><br><span class="line">        _head = head;</span><br><span class="line">        <span class="built_in">NSString</span> *name = [<span class="built_in">NSString</span> stringWithFormat:<span class="string">@"com.ThreadSafeStack.dispatchQueue.%@"</span>, [[<span class="built_in">NSUUID</span> UUID] UUIDString]];</span><br><span class="line">        _isolationQueue = dispatch_queue_create([name cStringUsingEncoding:<span class="built_in">NSASCIIStringEncoding</span>], DISPATCH_QUEUE_SERIAL);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">self</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">+ (<span class="built_in">BOOL</span>)supportsSecureCoding&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">YES</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Reference:</p><p><a href="https://xiaozhuanlan.com/ios-interview" target="_blank" rel="noopener">https://xiaozhuanlan.com/ios-interview</a> 《iOS 面试之道》</p><p>Concurrency programming / GCD<br><a href="https://developer.apple.com/documentation/dispatch" target="_blank" rel="noopener">https://developer.apple.com/documentation/dispatch</a><br><a href="https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html\#//apple\_ref/doc/uid/TP40008091-CH1-SW1" target="_blank" rel="noopener">https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html\#//apple\_ref/doc/uid/TP40008091-CH1-SW1</a></p><p>Threading<br><a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html\#//apple\_ref/doc/uid/10000057i-CH1-SW1" target="_blank" rel="noopener">https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/Introduction/Introduction.html\#//apple\_ref/doc/uid/10000057i-CH1-SW1</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;更多数据结构&quot;&gt;&lt;a href=&quot;#更多数据结构&quot; class=&quot;headerlink&quot; title=&quot;更多数据结构&quot;&gt;&lt;/a&gt;更多数据结构&lt;/h2&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="Swift" scheme="https://jasonhan1990.github.io/tags/Swift/"/>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="读书笔记" scheme="https://jasonhan1990.github.io/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
      <category term="iOS面试" scheme="https://jasonhan1990.github.io/tags/iOS%E9%9D%A2%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>《iOS面试之道》阅读笔记（1）</title>
    <link href="https://jasonhan1990.github.io/2018/08/27/ios-%E9%9D%A2%E8%AF%95%E4%B9%8B%E9%81%93-1/"/>
    <id>https://jasonhan1990.github.io/2018/08/27/ios-面试之道-1/</id>
    <published>2018-08-27T21:37:42.000Z</published>
    <updated>2018-10-02T02:25:36.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h2><a id="more"></a><h3 id="Array"><a href="#Array" class="headerlink" title="Array"></a>Array</h3><p>关于Swift的数组，有三种不同的形式：</p><ul><li><code>ContiguousArray</code>: 其实我之前也一直没有注意这个形式的数组，因为平时更多在写Objc，很少写Swift。ContiguousArray就是强制规划一个连续的空间来储存Elements。当用ContiguousArray来储存对象数据（<code>class</code>或<code>@objc</code>）时，其性能优于Array。</li><li><code>Array</code>: 当Array储存值类型的数据的时候，内存空间是连续的。但是当储存类型是对象（<code>class</code>或<code>@objc</code>）的时候，Array会自动桥接到NSArray上，内存可能不连续。其实可以看出，当Array和ContiguousArray都储存值类型（<code>struct</code>或<code>enumeration</code>）的话，他们的性能相当。</li><li><code>ArraySlice</code>: 数组片段，它的作用就是让我们更快和更高效地对一个大数组的其中一部分最处理。ArraySlice是不会创建新的存储空间的，它和原本的Array在内存上共享同一区域。但是，这并不意味修改ArraySlice中的元素会影响到原来的Array。</li></ul><p>更多:</p><h5 id="ContiguousArray的创建："><a href="#ContiguousArray的创建：" class="headerlink" title="ContiguousArray的创建："></a><code>ContiguousArray</code>的创建：</h5><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> cArray = <span class="type">ContiguousArray</span>&lt;<span class="type">Any</span>&gt;(repeating: <span class="number">0</span>, <span class="built_in">count</span>: <span class="number">3</span>)</span><br><span class="line"><span class="built_in">print</span>(type(of: cArray))  <span class="comment">// "ContiguousArray&lt;Any&gt;\n"</span></span><br></pre></td></tr></table></figure><h5 id="Array的count和capacity："><a href="#Array的count和capacity：" class="headerlink" title="Array的count和capacity："></a>Array的<code>count</code>和<code>capacity</code>：</h5><p>我们知道，当Array中的元素增加的时候，如果数组的内存不足，就需要新建一个更大的数组，然后从旧的数组中复制所有元素到新的数组里。现在的高级语言的Array都是Dynamic Array，你不需要自己去给数组扩容。为了提高数组扩的容的效率，底层代码都是成倍数的增加数组的大小。如Swift的Array的增长因子是2（<a href="https://blog.csdn.net/honglicu123/article/details/77541943" target="_blank" rel="noopener">阅读</a>）。所以Capacity和Count是不同的，Capacity是指这个数组的总大小，Count是现在所有存在元素的个数。例子：</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> cArray = <span class="type">ContiguousArray</span>&lt;<span class="type">Any</span>&gt;(repeating: <span class="number">0</span>, <span class="built_in">count</span>: <span class="number">3</span>)</span><br><span class="line"><span class="built_in">print</span>(cArray.<span class="built_in">count</span>)        <span class="comment">// 3</span></span><br><span class="line"><span class="built_in">print</span>(cArray.capacity)     <span class="comment">// 3</span></span><br><span class="line"></span><br><span class="line">cArray.append(<span class="number">9</span>)</span><br><span class="line"><span class="built_in">print</span>(cArray.<span class="built_in">count</span>)        <span class="comment">// 4</span></span><br><span class="line"><span class="built_in">print</span>(cArray.capacity)     <span class="comment">// 6</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 当removeAll的时候，数组的所有空间都会被释放掉</span></span><br><span class="line">cArray.removeAll()        </span><br><span class="line"><span class="built_in">print</span>(cArray.<span class="built_in">count</span>)        <span class="comment">// 0</span></span><br><span class="line"><span class="built_in">print</span>(cArray.capacity)     <span class="comment">// 0</span></span><br></pre></td></tr></table></figure><h5 id="Array的reserveCapacity-："><a href="#Array的reserveCapacity-：" class="headerlink" title="Array的reserveCapacity(_:)："></a>Array的<code>reserveCapacity(_:)</code>：</h5><p>正如上面所说，当数组扩容的时候是有性能损耗的。当你大概知道需要多大内存容量的数组的时候，就可以用<code>reserveCapacity(_:)</code>来创建和保持数组的大小，省去数组<code>Capacity</code>变化带来的性能损耗。</p><h5 id="ArraySlice的index并不总是开始于0："><a href="#ArraySlice的index并不总是开始于0：" class="headerlink" title="ArraySlice的index并不总是开始于0："></a>ArraySlice的index并不总是开始于0：</h5><p>ArraySlice会保留在原本数组中相同元素的index。</p><figure class="highlight swift"><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 class="keyword">let</span> absences = [<span class="number">0</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">4</span>, <span class="number">0</span>, <span class="number">3</span>, <span class="number">1</span>, <span class="number">0</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> midpoint = absences.<span class="built_in">count</span> / <span class="number">2</span></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="keyword">let</span> firstHalf = absences[..&lt;midpoint]</span><br><span class="line"><span class="keyword">let</span> secondHalf = absences[midpoint...]</span><br><span class="line"></span><br><span class="line">firstHalf[<span class="number">0</span>]    <span class="comment">// 0</span></span><br><span class="line">secondHalf[<span class="number">0</span>]   <span class="comment">// Fatal error: Index out of bounds</span></span><br></pre></td></tr></table></figure><h5 id="ArraySlice会持有一个对原数组的强应用："><a href="#ArraySlice会持有一个对原数组的强应用：" class="headerlink" title="ArraySlice会持有一个对原数组的强应用："></a>ArraySlice会持有一个对原数组的强应用：</h5><p>这意味着可能存在的内存溢出。在Swift文档中有如下建议：</p><blockquote><p>Important: Long-term storage of ArraySlice instances is discouraged. A slice holds a reference to the entire storage of a larger array, not just to the portion it presents, even after the original array’s lifetime ends. Long-term storage of a slice may therefore prolong the lifetime of elements that are no longer otherwise accessible, which can appear to be memory and object leakage.</p></blockquote><hr><h3 id="Set-And-Dictionary"><a href="#Set-And-Dictionary" class="headerlink" title="Set And Dictionary"></a>Set And Dictionary</h3><p>Set和Dictionary在查找上都是O(1)，这是源于他们都采用了hash。他们在存储时都是无序的。如果你有需求将一个自定义的类放入Set中或作为Dictionary的Key，那么这个类需要满足Hashable Protocal。</p><p>更多：</p><h5 id="Dictionary的value可以为nil吗："><a href="#Dictionary的value可以为nil吗：" class="headerlink" title="Dictionary的value可以为nil吗："></a>Dictionary的value可以为nil吗：</h5><p>可以的。当你在创建一个dictionary的时候，如果value为nil，则这个字典中所有的value都会转化为optional。<br>另外，我们知道在Swift中去删除一个Key-Value pair，我们只需要给这个key所对应的value赋值nil。那么当value为nil时，这个方法会不会失效？答案是不会。<br>最后，当一个value是nil的时候，用if let判断时会怎样？答案是if let会通过，value为nil。例子：</p><figure class="highlight swift"><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"><span class="keyword">var</span> dic = [<span class="string">"a"</span>: <span class="number">1</span>,</span><br><span class="line">           <span class="string">"b"</span>: <span class="literal">nil</span>,</span><br><span class="line">           <span class="string">"c"</span>: <span class="number">3</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> dicA = [<span class="string">"a"</span>: <span class="number">1</span>,</span><br><span class="line">            <span class="string">"b"</span>: <span class="number">2</span>,</span><br><span class="line">            <span class="string">"c"</span>: <span class="number">3</span>]</span><br><span class="line">            </span><br><span class="line"><span class="built_in">print</span>(dic)     <span class="comment">// ["b": nil, "a": Optional(1), "c": Optional(3)]</span></span><br><span class="line"><span class="built_in">print</span>(dicA)    <span class="comment">// ["b": 2, "a": 1, "c": 3]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// if let</span></span><br><span class="line"><span class="keyword">if</span> <span class="keyword">let</span> valueFromB = dic[<span class="string">"b"</span>] &#123;</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">"b has value: <span class="subst">\(valueFromB)</span>"</span>)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">"b has no value"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 输出: b has value: nil</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 删除b</span></span><br><span class="line">dic[<span class="string">"b"</span>] = <span class="literal">nil</span></span><br><span class="line"><span class="built_in">print</span>(dic)     <span class="comment">// ["a": Optional(1), "c": Optional(3)]</span></span><br></pre></td></tr></table></figure><hr><h3 id="String"><a href="#String" class="headerlink" title="String"></a>String</h3><p>对比与Objective-C，swift把很多类都变成了struct，字符串也不例外。这样的好处是增加了代码的安全，因为Swift为你最好了Copy-on-write，你也不用再像写ObjC那样要特别留意用copy关键字和动不动就要copy一下。当然，通过用inout关键字也是能实现传递引用的。</p><p>更多：</p><h5 id="获得所有字符："><a href="#获得所有字符：" class="headerlink" title="获得所有字符："></a>获得所有字符：</h5><p>用一个Array来获得一个所有字符的数组。</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> string = <span class="string">"abc"</span>        <span class="comment">// "abc"</span></span><br><span class="line"><span class="keyword">let</span> chars = <span class="type">Array</span>(string) <span class="comment">// ["a", "b", "c"]</span></span><br></pre></td></tr></table></figure><h5 id="subString："><a href="#subString：" class="headerlink" title="subString："></a>subString：</h5><p>String和Array很像，当你计算出一个range后，你就可以获得子字符串。</p><figure class="highlight swift"><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"><span class="keyword">let</span> fqdn = <span class="string">"useyourloaf.com"</span></span><br><span class="line"><span class="keyword">let</span> tldEndIndex = fqdn.endIndex</span><br><span class="line"><span class="keyword">let</span> tldStartIndex = fqdn.index(tldEndIndex, offsetBy: -<span class="number">3</span>)</span><br><span class="line"><span class="keyword">let</span> range = <span class="type">Range</span>(uncheckedBounds: (lower: tldStartIndex, upper: tldEndIndex))</span><br><span class="line">fqdn[range]    <span class="comment">// "com"</span></span><br><span class="line"></span><br><span class="line">“<span class="type">From</span> https:<span class="comment">//useyourloaf.com/blog/swift-string-cheat-sheet/”</span></span><br></pre></td></tr></table></figure><p>Reference:<br><a href="https://xiaozhuanlan.com/ios-interview" target="_blank" rel="noopener">https://xiaozhuanlan.com/ios-interview</a> 《iOS 面试之道》<br><a href="https://useyourloaf.com" target="_blank" rel="noopener">https://useyourloaf.com</a><br><a href="https://swiftdoc.org/" target="_blank" rel="noopener">https://swiftdoc.org/</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;数据结构&quot;&gt;&lt;a href=&quot;#数据结构&quot; class=&quot;headerlink&quot; title=&quot;数据结构&quot;&gt;&lt;/a&gt;数据结构&lt;/h2&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="Swift" scheme="https://jasonhan1990.github.io/tags/Swift/"/>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="读书笔记" scheme="https://jasonhan1990.github.io/tags/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/"/>
    
      <category term="iOS面试" scheme="https://jasonhan1990.github.io/tags/iOS%E9%9D%A2%E8%AF%95/"/>
    
  </entry>
  
  <entry>
    <title>AVPlayer - AVFoundation</title>
    <link href="https://jasonhan1990.github.io/2017/08/21/avfoundation-avplayer/"/>
    <id>https://jasonhan1990.github.io/2017/08/21/avfoundation-avplayer/</id>
    <published>2017-08-22T02:37:17.000Z</published>
    <updated>2018-09-27T02:43:26.000Z</updated>
    
    <content type="html"><![CDATA[<h4 id="AVPlayer"><a href="#AVPlayer" class="headerlink" title="AVPlayer"></a>AVPlayer</h4><p>AVFoundation provides a controller class <code>AVPlayer</code> to play timed audio-visual media. The AVPlayer can handle playback of local, progressively downloaded and streamed media conforming HLS protocol. </p><a id="more"></a><p>AVPlayer is just a controller. It can play, pause, stop and jump to a certain time in a video, but it can’t show a video to users’ eyes. In order to display the video in user interface, we need use <code>AVPlayerLayer</code>.</p><h4 id="AVPlayerLayer"><a href="#AVPlayerLayer" class="headerlink" title="AVPlayerLayer"></a>AVPlayerLayer</h4><p><code>AVPlayerLayer</code> is built on the top of Core Animation. <code>AVPlayerLayer</code> extends the <code>CALayer</code> class, so it can be used like any other CALayer and can be set as the backing layer for <code>UIView</code> or <code>NSView</code> or can be added into an existing layer hierarchy.<br><code>AVPlayerLayer</code> has a property <code>videoGravity</code> to specifies how the video is displayed within a player layer’s bounds.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="built_in">NSString</span> * <span class="built_in">AVLayerVideoGravity</span> <span class="built_in">NS_STRING_ENUM</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    @constant       AVLayerVideoGravityResizeAspect</span></span><br><span class="line"><span class="comment">    @abstract       Preserve aspect ratio; fit within layer bounds.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="built_in">AVF_EXPORT</span> <span class="built_in">AVLayerVideoGravity</span> <span class="keyword">const</span> <span class="built_in">AVLayerVideoGravityResizeAspect</span> <span class="built_in">NS_AVAILABLE</span>(<span class="number">10</span>_7, <span class="number">4</span>_0); <span class="comment">// default</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    @constant       AVLayerVideoGravityResizeAspectFill</span></span><br><span class="line"><span class="comment">    @abstract       Preserve aspect ratio; fill layer bounds.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="built_in">AVF_EXPORT</span> <span class="built_in">AVLayerVideoGravity</span> <span class="keyword">const</span> <span class="built_in">AVLayerVideoGravityResizeAspectFill</span> <span class="built_in">NS_AVAILABLE</span>(<span class="number">10</span>_7, <span class="number">4</span>_0);</span><br><span class="line"></span><br><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    @constant       AVLayerVideoGravityResize</span></span><br><span class="line"><span class="comment">    @abstract       Stretch to fill layer bounds.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="built_in">AVF_EXPORT</span> <span class="built_in">AVLayerVideoGravity</span> <span class="keyword">const</span> <span class="built_in">AVLayerVideoGravityResize</span> <span class="built_in">NS_AVAILABLE</span>(<span class="number">10</span>_7, <span class="number">4</span>_0);</span><br></pre></td></tr></table></figure><h4 id="AVPlayerItem"><a href="#AVPlayerItem" class="headerlink" title="AVPlayerItem"></a>AVPlayerItem</h4><p><code>AVPlayerItem</code> stores the reference to <code>AVAsset</code> objects. <code>AVPlayerItem</code> is a dynamic object. Many of its property values can be changed during the item’s preparation and playback. We can use KVO to observe these changes as they occur. For instance, the <code>AVPlayerItem</code> has a property status to indicate if the item is ready for playback. When you first create a player item, the status is <code>AVPlayerItemStatusUnknown</code>, meaning it’s not ready for playback. We need to wait until its status changes to <code>AVPlayerItemStatusReadyToPlay</code> before it’s ready to use.</p><h4 id="Creating-AVPlayer"><a href="#Creating-AVPlayer" class="headerlink" title="Creating AVPlayer"></a>Creating AVPlayer</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Example for create an avplayer</span></span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">strong</span>, <span class="keyword">nonatomic</span>) <span class="built_in">AVPlayer</span> * player;</span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">strong</span>, <span class="keyword">nonatomic</span>) <span class="built_in">AVPlayerItem</span> * playerItem;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)initPlayer:(<span class="built_in">NSURL</span> *)url &#123;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// Create AVAsset</span></span><br><span class="line">  <span class="built_in">AVAsset</span> *asset = [<span class="built_in">AVAsset</span> assetWithURL:url];</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// Create an avplayer item with asset</span></span><br><span class="line">  playerItem = [<span class="built_in">AVPlayerItem</span> playerItemWithAsset:asset];</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// register KVO for observing the change of status</span></span><br><span class="line">  <span class="built_in">NSKeyValueObservingOptions</span> options =</span><br><span class="line">        <span class="built_in">NSKeyValueObservingOptionOld</span> | <span class="built_in">NSKeyValueObservingOptionNew</span>;</span><br><span class="line">  </span><br><span class="line">  [playItem addObserver:<span class="keyword">self</span> </span><br><span class="line">             forKeyPath:<span class="string">@"status"</span> </span><br><span class="line">                options:options </span><br><span class="line">                context:&amp;PlayerItemContext];</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// create avplayer with player item</span></span><br><span class="line">  <span class="keyword">self</span>.player = [<span class="built_in">AVPlayer</span> playerWithPlayerItem:playerItem];</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// create a player layer to display video content</span></span><br><span class="line">  <span class="built_in">AVPlayerLayer</span> *playerLayer = [<span class="built_in">AVPlayerLayer</span> playerLayerWithPlayer:<span class="keyword">self</span>.player];</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// add player layer to current view hierarchy</span></span><br><span class="line">  [<span class="keyword">self</span>.view.layer addSublayer:playerLayer];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)observeValueForKeyPath:(<span class="built_in">NSString</span> *)keyPath</span><br><span class="line">                      ofObject:(<span class="keyword">id</span>)object</span><br><span class="line">                        change:(<span class="built_in">NSDictionary</span>&lt;<span class="built_in">NSString</span> *,<span class="keyword">id</span>&gt; *)change</span><br><span class="line">                       context:(<span class="keyword">void</span> *)context &#123;</span><br><span class="line">    <span class="comment">// Only handle observations for the PlayerItemContext</span></span><br><span class="line">    <span class="keyword">if</span> (context != &amp;PlayerItemContext) &#123;</span><br><span class="line">        [<span class="keyword">super</span> observeValueForKeyPath:keyPath ofObject:object change:change context:context];</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">if</span> ([keyPath isEqualToString:<span class="string">@"status"</span>]) &#123;</span><br><span class="line">        <span class="built_in">AVPlayerItemStatus</span> status = <span class="built_in">AVPlayerItemStatusUnknown</span>;</span><br><span class="line">        <span class="comment">// Get the status change from the change dictionary</span></span><br><span class="line">        <span class="built_in">NSNumber</span> *statusNumber = change[<span class="built_in">NSKeyValueChangeNewKey</span>];</span><br><span class="line">        <span class="keyword">if</span> ([statusNumber isKindOfClass:[<span class="built_in">NSNumber</span> <span class="keyword">class</span>]]) &#123;</span><br><span class="line">            status = statusNumber.integerValue;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// Switch over the status</span></span><br><span class="line">        <span class="keyword">switch</span> (status) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="built_in">AVPlayerItemStatusReadyToPlay</span>:</span><br><span class="line">                <span class="comment">// Ready to Play</span></span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="built_in">AVPlayerItemStatusFailed</span>:</span><br><span class="line">                <span class="comment">// Failed. Examine AVPlayerItem.error</span></span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="built_in">AVPlayerItemStatusUnknown</span>:</span><br><span class="line">                <span class="comment">// Not ready</span></span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Manage-Playback-Time"><a href="#Manage-Playback-Time" class="headerlink" title="Manage Playback Time"></a>Manage Playback Time</h4><p><code>CMTime</code> is the structure describing media time. A CMTime is represented as a rational number, with a numerator (an int64_t value), and a denominator (an int32_t timescale).</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="keyword">struct</span>&#123;    </span><br><span class="line">    <span class="built_in">CMTimeValue</span>    value; <span class="comment">// think as the total number of frames</span></span><br><span class="line">    <span class="built_in">CMTimeScale</span>    timescale; <span class="comment">// think as the frame per second</span></span><br><span class="line">    <span class="built_in">CMTimeFlags</span>    flags;      </span><br><span class="line">    <span class="built_in">CMTimeEpoch</span>    epoch;</span><br><span class="line">&#125; <span class="built_in">CMTime</span>;</span><br></pre></td></tr></table></figure><p><code>AVPlayerItem</code> has a duration property which is a object of CMTime. We can get the total duration in seconds by </p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">double</span> seconds = playerItem.duration.value / playerItem.duration.timescale;</span><br><span class="line"></span><br><span class="line"><span class="comment">// or</span></span><br><span class="line"><span class="keyword">double</span> seconds = <span class="built_in">CMTimeGetSeconds</span>(playerItem.duration)</span><br></pre></td></tr></table></figure><p>We can create a CMTime by <code>CMTimeMake(int64_t value, int32_t timescale)</code></p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">CMTime</span> t1 = <span class="built_in">CMTimeMake</span>(<span class="number">1</span>, <span class="number">10</span>); <span class="comment">// 0.1s</span></span><br><span class="line"><span class="built_in">CMTime</span> t2 = <span class="built_in">CMTimeMake</span>(<span class="number">2</span>, <span class="number">1</span>); <span class="comment">// 2s</span></span><br></pre></td></tr></table></figure><p><code>AVPlayer</code> has this functions to manage the time.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><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"><span class="comment">/* Returns the current time of the current player item. */</span></span><br><span class="line">- (<span class="built_in">CMTime</span>)currentTime;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Sets the current playback time to the time specified by the date object.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">- (<span class="keyword">void</span>)seekToDate:(<span class="built_in">NSDate</span> *)date;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Sets the current playback time to the specified time and executes the specified block when the seek operation completes or is interrupted. */</span></span><br><span class="line">- (<span class="keyword">void</span>)seekToDate:(<span class="built_in">NSDate</span> *)date completionHandler:(<span class="keyword">void</span> (^)(<span class="built_in">BOOL</span> finished))completionHandler <span class="built_in">NS_AVAILABLE</span>(<span class="number">10</span>_7, <span class="number">5</span>_0);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Sets the current playback time to the specified time. */</span></span><br><span class="line">- (<span class="keyword">void</span>)seekToTime:(<span class="built_in">CMTime</span>)time;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Sets the current playback time within a specified time bound. */</span></span><br><span class="line">- (<span class="keyword">void</span>)seekToTime:(<span class="built_in">CMTime</span>)time toleranceBefore:(<span class="built_in">CMTime</span>)toleranceBefore toleranceAfter:(<span class="built_in">CMTime</span>)toleranceAfter;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Sets the current playback time to the specified time and executes the specified block when the seek operation completes or is interrupted.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">- (<span class="keyword">void</span>)seekToTime:(<span class="built_in">CMTime</span>)time completionHandler:(<span class="keyword">void</span> (^)(<span class="built_in">BOOL</span> finished))completionHandler <span class="built_in">NS_AVAILABLE</span>(<span class="number">10</span>_7, <span class="number">5</span>_0);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Sets the current playback time within a specified time bound and invokes the specified block when the seek operation has either been completed or been interrupted.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">- (<span class="keyword">void</span>)seekToTime:(<span class="built_in">CMTime</span>)time toleranceBefore:(<span class="built_in">CMTime</span>)toleranceBefore toleranceAfter:(<span class="built_in">CMTime</span>)toleranceAfter completionHandler:(<span class="keyword">void</span> (^)(<span class="built_in">BOOL</span> finished))completionHandler <span class="built_in">NS_AVAILABLE</span>(<span class="number">10</span>_7, <span class="number">5</span>_0);</span><br></pre></td></tr></table></figure><h4 id="Observing-time"><a href="#Observing-time" class="headerlink" title="Observing time"></a>Observing time</h4><p><code>AVPlayer</code> also provides methods for us to observing time.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Requests the periodic invocation of a given block during playback to report changing time. */</span></span><br><span class="line">- (<span class="keyword">id</span>)addPeriodicTimeObserverForInterval:(<span class="built_in">CMTime</span>)interval queue:(<span class="keyword">nullable</span> <span class="built_in">dispatch_queue_t</span>)queue usingBlock:(<span class="keyword">void</span> (^)(<span class="built_in">CMTime</span> time))block;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Requests the invocation of a block when specified times are traversed during normal playback. */</span></span><br><span class="line">- (<span class="keyword">id</span>)addBoundaryTimeObserverForTimes:(<span class="built_in">NSArray</span>&lt;<span class="built_in">NSValue</span> *&gt; *)times queue:(<span class="keyword">nullable</span> <span class="built_in">dispatch_queue_t</span>)queue usingBlock:(<span class="keyword">void</span> (^)(<span class="keyword">void</span>))block;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* Cancels a previously registered periodic or boundary time observer. */</span></span><br><span class="line">- (<span class="keyword">void</span>)removeTimeObserver:(<span class="keyword">id</span>)observer;</span><br></pre></td></tr></table></figure><p>For example, we can add update the player transport UI by adding a periodic time observer.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// update transport UI</span></span><br><span class="line">- (<span class="keyword">void</span>)addPeriodicTimeObserver &#123;</span><br><span class="line">    <span class="comment">// Invoke callback every half second</span></span><br><span class="line">    <span class="built_in">CMTime</span> interval = <span class="built_in">CMTimeMakeWithSeconds</span>(<span class="number">0.5</span>, <span class="built_in">NSEC_PER_SEC</span>);</span><br><span class="line">    <span class="comment">// Queue on which to invoke the callback</span></span><br><span class="line">    <span class="built_in">dispatch_queue_t</span> mainQueue = dispatch_get_main_queue();</span><br><span class="line">    <span class="comment">// Add time observer</span></span><br><span class="line">    __<span class="keyword">weak</span> <span class="keyword">typeof</span>(<span class="keyword">self</span>)WeakSelf = <span class="keyword">self</span>;</span><br><span class="line">    <span class="keyword">self</span>.timeObserverToken =</span><br><span class="line">        [<span class="keyword">self</span>.player addPeriodicTimeObserverForInterval:interval</span><br><span class="line">                                                  queue:mainQueue</span><br><span class="line">                                             usingBlock:^(<span class="built_in">CMTime</span> time) &#123;</span><br><span class="line">                                                 <span class="comment">// Use weak reference to self</span></span><br><span class="line">                                                 <span class="comment">// Update player transport UI</span></span><br><span class="line">                                                 <span class="keyword">float</span> currentPlayTime = (<span class="keyword">float</span>)item.currentTime.value/ item.currentTime.timescale;</span><br><span class="line">                                                 [WeakSelf updateTransportBar:currentPlayTime];</span><br><span class="line">                                             &#125;];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)dealloc &#123;</span><br><span class="line">  [_player removeTimeObserver:_timeObserverToken];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Handle-Playback-End"><a href="#Handle-Playback-End" class="headerlink" title="Handle Playback End"></a>Handle Playback End</h4><p><code>AVPlayerItem</code> has several notifications for different activities.</p><ol><li><code>AVPlayerItemTimeJumpedNotification</code></li><li><code>AVPlayerItemDidPlayToEndTimeNotification</code></li><li><code>AVPlayerItemFailedToPlayToEndTimeNotification</code></li><li><code>AVPlayerItemPlaybackStalledNotification</code></li><li><code>AVPlayerItemNewAccessLogEntryNotification</code></li><li><code>AVPlayerItemNewErrorLogEntryNotification</code></li></ol><p>We can use these to track current playback. For handling playback end:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Add Observer</span></span><br><span class="line">[[<span class="built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="keyword">self</span></span><br><span class="line">                                         selector:<span class="keyword">@selector</span>(handlePlayerDidFinishPlaying:)</span><br><span class="line">                                             name:<span class="built_in">AVPlayerItemDidPlayToEndTimeNotification</span></span><br><span class="line">                                           object:[<span class="keyword">self</span>.player currentItem]];</span><br><span class="line">                                           </span><br><span class="line">- (<span class="keyword">void</span>)handlePlayerDidFinishPlaying:(<span class="built_in">NSNotification</span> *)notification &#123;</span><br><span class="line">    <span class="built_in">AVPlayerItem</span> *playerItem = (<span class="built_in">AVPlayerItem</span> *)notification.object;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Jump to the beginning of the video</span></span><br><span class="line">    [playerItem seekToTime:kCMTimeZero];</span><br><span class="line">    <span class="comment">// pause the video</span></span><br><span class="line">    [player pause];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Handle-Interruption"><a href="#Handle-Interruption" class="headerlink" title="Handle Interruption"></a>Handle Interruption</h4><p>When AVPlayer got interrupted, current playback will pause. We can listen to the notification comes from AVAudioSession, but don’t forget to activate AVAudioSession.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Configure AVAudioSession and activate it when you init your avplayer controller</span></span><br><span class="line"><span class="comment">// Setup audio session catagory, use playback for video playback</span></span><br><span class="line"><span class="built_in">AVAudioSession</span> *session = [<span class="built_in">AVAudioSession</span> sharedInstance];</span><br><span class="line">        </span><br><span class="line"><span class="built_in">NSError</span> *error;</span><br><span class="line"><span class="keyword">if</span> (![session setCategory:<span class="built_in">AVAudioSessionCategoryPlayback</span> error:&amp;error]) &#123;</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"Category Error: %@"</span>, [error localizedDescription]);</span><br><span class="line">&#125;</span><br><span class="line">        </span><br><span class="line"><span class="keyword">if</span> (![session setActive:<span class="literal">YES</span> error:&amp;error]) &#123;</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"Activation Error: %@"</span>, [error localizedDescription]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Add Observer</span></span><br><span class="line">[[<span class="built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="keyword">self</span></span><br><span class="line">                                         selector:<span class="keyword">@selector</span>(handleSessionInterruption:)</span><br><span class="line">                                             name:<span class="built_in">AVAudioSessionInterruptionNotification</span></span><br><span class="line">                                           object:<span class="literal">nil</span>];</span><br><span class="line">                                           </span><br><span class="line">- (<span class="keyword">void</span>)handleSessionInterruption:(<span class="built_in">NSNotification</span> *)notification &#123;</span><br><span class="line">    <span class="built_in">AVAudioSessionInterruptionType</span> type = [notification.userInfo[<span class="built_in">AVAudioSessionInterruptionTypeKey</span>] unsignedIntegerValue];</span><br><span class="line">    <span class="keyword">if</span> (type == <span class="built_in">AVAudioSessionInterruptionTypeBegan</span>) &#123;</span><br><span class="line">    </span><br><span class="line">        <span class="comment">// pause the video</span></span><br><span class="line">        [<span class="keyword">self</span>.player pause];</span><br><span class="line">        </span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (type == <span class="built_in">AVAudioSessionInterruptionTypeEnded</span>) &#123;</span><br><span class="line">        <span class="comment">// resume the video ??</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Handle-Route-Change"><a href="#Handle-Route-Change" class="headerlink" title="Handle Route Change"></a>Handle Route Change</h4><p>We will use the notification comes from <code>AVAudioSession</code> again to handle route change.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Add Observer</span></span><br><span class="line">[[<span class="built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="keyword">self</span></span><br><span class="line">                                         selector:<span class="keyword">@selector</span>(handleRouteChange:)</span><br><span class="line">                                             name:<span class="built_in">AVAudioSessionRouteChangeNotification</span></span><br><span class="line">                                           object:<span class="literal">nil</span>];</span><br><span class="line">                                           </span><br><span class="line">- (<span class="keyword">void</span>)handleRouteChange:(<span class="built_in">NSNotification</span> *)notification &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">AVAudioSessionRouteChangeReason</span> reason = [notification.userInfo[<span class="built_in">AVAudioSessionRouteChangeReasonKey</span>] unsignedIntegerValue];</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (reason == <span class="built_in">AVAudioSessionRouteChangeReasonOldDeviceUnavailable</span>) &#123;</span><br><span class="line">        <span class="built_in">AVAudioSessionRouteDescription</span> *preRoute = notification.userInfo[<span class="built_in">AVAudioSessionRouteChangePreviousRouteKey</span>];</span><br><span class="line">        <span class="built_in">NSString</span> *portType = [[preRoute.outputs firstObject] portType];</span><br><span class="line">        <span class="keyword">if</span> ([portType isEqualToString:<span class="built_in">AVAudioSessionPortHeadphones</span>]) &#123;</span><br><span class="line">            <span class="comment">// This notification was send from other thread, pop up error message under main thread</span></span><br><span class="line">            <span class="built_in">dispatch_async</span>(dispatch_get_main_queue(), ^&#123;</span><br><span class="line">                <span class="comment">// pause the video</span></span><br><span class="line">                [<span class="keyword">self</span> pause];</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Handle-Fail-Play-To-End"><a href="#Handle-Fail-Play-To-End" class="headerlink" title="Handle Fail Play To End"></a>Handle Fail Play To End</h4><p><code>AVPlayerItemFailedToPlayToEndTimeNotification</code>. In most cases, we will get this notification when we play streaming video and you got network problem.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Add Observer</span></span><br><span class="line">[[<span class="built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="keyword">self</span></span><br><span class="line">                                         selector:<span class="keyword">@selector</span>(handleAVPlayerItemFailedToPlayToEndTime:) </span><br><span class="line">                                             name:<span class="built_in">AVPlayerItemFailedToPlayToEndTimeNotification</span></span><br><span class="line">                                           object:<span class="literal">nil</span>];</span><br><span class="line">                                           </span><br><span class="line">- (<span class="keyword">void</span>)handleAVPlayerItemFailedToPlayToEndTime:(<span class="built_in">NSNotification</span> *)notification &#123;</span><br><span class="line">    <span class="built_in">NSError</span> *error = notification.userInfo[<span class="built_in">AVPlayerItemFailedToPlayToEndTimeErrorKey</span>];</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// This notification was send from other thread, pop up error message under main thread</span></span><br><span class="line">    <span class="built_in">dispatch_async</span>(dispatch_get_main_queue(), ^&#123;</span><br><span class="line">        [<span class="keyword">self</span> popErrorAlert:error];</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Here is the <a href="https://github.com/JasonHan1990/AVFoundation-Learning/tree/master/03-AVPlayer" target="_blank" rel="noopener">Test App</a></p><div class="video-container"><iframe src="//player.vimeo.com/video/232612199" frameborder="0" allowfullscreen></iframe></div>]]></content>
    
    <summary type="html">
    
      &lt;h4 id=&quot;AVPlayer&quot;&gt;&lt;a href=&quot;#AVPlayer&quot; class=&quot;headerlink&quot; title=&quot;AVPlayer&quot;&gt;&lt;/a&gt;AVPlayer&lt;/h4&gt;&lt;p&gt;AVFoundation provides a controller class &lt;code&gt;AVPlayer&lt;/code&gt; to play timed audio-visual media. The AVPlayer can handle playback of local, progressively downloaded and streamed media conforming HLS protocol. &lt;/p&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="AVFoundation" scheme="https://jasonhan1990.github.io/tags/AVFoundation/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="AVPlayer" scheme="https://jasonhan1990.github.io/tags/AVPlayer/"/>
    
  </entry>
  
  <entry>
    <title>AVAssets - AVFoundation</title>
    <link href="https://jasonhan1990.github.io/2017/08/21/avfoundation-avassets/"/>
    <id>https://jasonhan1990.github.io/2017/08/21/avfoundation-avassets/</id>
    <published>2017-08-22T01:43:54.000Z</published>
    <updated>2018-09-27T01:50:30.000Z</updated>
    
    <content type="html"><![CDATA[<p><code>AVAsset</code> is an abstract, immutable class providing a composite representation of a media resource, modeling the static attributes of the media as a whole, such as its title, duration, and metadata. AVAsset is not the media itself, but acts as a container for timed media. It is composed of one or more media tracks along with metadata describing its contents.</p><a id="more"></a><p><code>AVAsset</code> confirms the <code>AVAsynchronousKeyValueLoading</code> protocol. We can querying an asset’s properties asynchronously.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// check for status for a key</span></span><br><span class="line">- (<span class="built_in">AVKeyValueStatus</span>)statusOfValueForKey:(<span class="built_in">NSString</span> *)key error:(<span class="built_in">NSError</span> * _Nullable * _Nullable)outError;</span><br><span class="line"><span class="comment">// asynchronously load properties by given keys </span></span><br><span class="line">- (<span class="keyword">void</span>)loadValuesAsynchronouslyForKeys:(<span class="built_in">NSArray</span>&lt;<span class="built_in">NSString</span> *&gt; *)keys completionHandler:(<span class="keyword">nullable</span> <span class="keyword">void</span> (^)(<span class="keyword">void</span>))handler;</span><br></pre></td></tr></table></figure><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// example </span></span><br><span class="line"><span class="comment">// Load the asset's "playable" key</span></span><br><span class="line">[asset loadValuesAsynchronouslyForKeys:@[<span class="string">@"playable"</span>] completionHandler:^&#123;</span><br><span class="line">    <span class="built_in">NSError</span> *error = <span class="literal">nil</span>;</span><br><span class="line">    <span class="built_in">AVKeyValueStatus</span> status =</span><br><span class="line">        [asset statusOfValueForKey:<span class="string">@"playable"</span> error:&amp;error];</span><br><span class="line">    <span class="keyword">switch</span> (status) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="built_in">AVKeyValueStatusLoaded</span>:</span><br><span class="line">            <span class="comment">// Successfully loaded, continue processing</span></span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="built_in">AVKeyValueStatusFailed</span>:</span><br><span class="line">            <span class="comment">// Examine NSError pointer to determine failure</span></span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="built_in">AVKeyValueStatusCancelled</span>:</span><br><span class="line">            <span class="comment">// Loading cancelled</span></span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            <span class="comment">// Handle all other cases</span></span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;];</span><br></pre></td></tr></table></figure><p>Note that:<br>The completionHandler block will be called only once per invocation of loadValuesAsynchronouslyForKeys:completionHandler:, no matter how many keys you pass to this methods.<br>We need to call status statusOfValueForKey:error: on each property you requested.</p><p><a href="https://developer.apple.com/documentation/avfoundation/avasset" target="_blank" rel="noopener">https://developer.apple.com/documentation/avfoundation/avasset</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;code&gt;AVAsset&lt;/code&gt; is an abstract, immutable class providing a composite representation of a media resource, modeling the static attributes of the media as a whole, such as its title, duration, and metadata. AVAsset is not the media itself, but acts as a container for timed media. It is composed of one or more media tracks along with metadata describing its contents.&lt;/p&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="AVFoundation" scheme="https://jasonhan1990.github.io/tags/AVFoundation/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="AVAssets" scheme="https://jasonhan1990.github.io/tags/AVAssets/"/>
    
  </entry>
  
  <entry>
    <title>AVAudioRecorder - AVFoundation</title>
    <link href="https://jasonhan1990.github.io/2017/08/16/avfoundation-avaudiorecorder/"/>
    <id>https://jasonhan1990.github.io/2017/08/16/avfoundation-avaudiorecorder/</id>
    <published>2017-08-16T21:38:24.000Z</published>
    <updated>2018-09-25T22:27:58.000Z</updated>
    
    <content type="html"><![CDATA[<p><code>AVAudioRecorder</code> is also built on top of Audio Queue Services. It provides capability to:</p><ul><li>Record until user stop the recording</li><li>Record for a specified duration</li><li>Pause and resume recording</li><li>Audio-level metering </li></ul><a id="more"></a><p>For recording and playback, we should choose <code>AVAudioSessionCategoryPlayAndRecord</code> for <code>AVAudioSession</code> category.<br>In order to use the microphone on our device, we need add microphone usage key to application.plist file.</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">key</span>&gt;</span>NSMicrophoneUsageDescription<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">string</span>&gt;</span>Need to use the microphone to record<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="Create-AVAudioRecorder"><a href="#Create-AVAudioRecorder" class="headerlink" title="Create AVAudioRecorder"></a>Create AVAudioRecorder</h4><p>To create an <code>AVAudioRecorder</code>, we need a url to specify a location to record to, a dictionary of settings for the recording session and output error.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">instancetype</span>)initWithURL:(<span class="built_in">NSURL</span> *)url settings:(<span class="built_in">NSDictionary</span>&lt;<span class="built_in">NSString</span> *,<span class="keyword">id</span>&gt; *)settings error:(<span class="built_in">NSError</span> * _Nullable *)outError;</span><br></pre></td></tr></table></figure><h4 id="Configure-recording-session"><a href="#Configure-recording-session" class="headerlink" title="Configure recording session"></a>Configure recording session</h4><p>We can configure several different things for our recording session. The general settings are audio data format, sampling rate and number of channels. </p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">NSMutableDictionary</span> *setting = [<span class="built_in">NSMutableDictionary</span> dictionary];</span><br><span class="line"><span class="comment">/* set format </span></span><br><span class="line"><span class="comment">** Note: the audio format we specify must be compatible with the tpye defined in the url argument. For example,</span></span><br><span class="line"><span class="comment">** .wav pairs to kAudioFormatLinearPCM</span></span><br><span class="line"><span class="comment">** .aac .m4a pair to kAudioFormatMPEG4AAC</span></span><br><span class="line"><span class="comment">** .alac pairs to kAudioFormatAppleLossless</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">[setting setValue:@(kAudioFormatMPEG4AAC) forKey:<span class="built_in">AVFormatIDKey</span>];</span><br><span class="line"><span class="comment">/* set sampling rate</span></span><br><span class="line"><span class="comment">** Standard sampling rate for audio: 8kHz, 16kHz, 22.05kHz, 44.1kHz</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">[setting setValue:@(<span class="number">16000.0</span>) forKey:<span class="built_in">AVSampleRateKey</span>];</span><br><span class="line"><span class="comment">/* set channal</span></span><br><span class="line"><span class="comment">** 1 is for single channel, 2 is for stereo</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line">[setting setValue:@(<span class="number">1</span>) forKey:<span class="built_in">AVNumberOfChannelsKey</span>];</span><br></pre></td></tr></table></figure><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// example for creating a AVAudioRecorder</span></span><br><span class="line"><span class="comment">// create store url</span></span><br><span class="line"><span class="built_in">NSString</span> *urlString = [<span class="built_in">NSSearchPathForDirectoriesInDomains</span>(<span class="built_in">NSDocumentDirectory</span>, <span class="built_in">NSUserDomainMask</span>, <span class="literal">YES</span>) objectAtIndex:<span class="number">0</span>];</span><br><span class="line"><span class="built_in">NSDate</span> *now = [<span class="built_in">NSDate</span> date];</span><br><span class="line"><span class="built_in">NSDateFormatter</span> *dateFormatter = [[<span class="built_in">NSDateFormatter</span> alloc] init];</span><br><span class="line">[dateFormatter setDateFormat:<span class="string">@"yyyyMMddHHmmssSSS"</span>];</span><br><span class="line">urlString = [urlString stringByAppendingFormat:<span class="string">@"%@-MySound.acc"</span>, [dateFormatter stringFromDate:now]];</span><br><span class="line"><span class="built_in">NSURL</span> *url = [<span class="built_in">NSURL</span> fileURLWithPath:urlString];</span><br><span class="line"></span><br><span class="line"><span class="comment">// set audio recording setting</span></span><br><span class="line"><span class="built_in">NSMutableDictionary</span> *setting = @&#123;</span><br><span class="line">  <span class="built_in">AVFormatIDKey</span>: @(kAudioFormatMPEG4AAC),</span><br><span class="line">  <span class="built_in">AVSampleRateKey</span>: @(<span class="number">16000.0</span>),</span><br><span class="line">  <span class="built_in">AVNumberOfChannelsKey</span>: @(<span class="number">1</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">NSError</span> *error;</span><br><span class="line"></span><br><span class="line"><span class="built_in">AVAudioRecorder</span> *recorder = [[<span class="built_in">AVAudioRecorder</span> alloc] initWithURL:url settings:setting error:&amp;error];</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (recorder) &#123;</span><br><span class="line">  <span class="comment">// configure recorder</span></span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">  <span class="comment">// output the error</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Controlling-Recording"><a href="#Controlling-Recording" class="headerlink" title="Controlling Recording"></a>Controlling Recording</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* when we call this method, the program creates an audio file at the location specified by the url we created */</span></span><br><span class="line">- (<span class="built_in">BOOL</span>)prepareToRecord;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* all record methods will implicitly call prepareToRecord() */</span></span><br><span class="line">- (<span class="built_in">BOOL</span>)record;</span><br><span class="line">- (<span class="built_in">BOOL</span>)recordAtTime:(<span class="built_in">NSTimeInterval</span>)time;</span><br><span class="line">- (<span class="built_in">BOOL</span>)recordForDuration:(<span class="built_in">NSTimeInterval</span>) duration;</span><br><span class="line">- (<span class="built_in">BOOL</span>)recordAtTime:(<span class="built_in">NSTimeInterval</span>)time forDuration:(<span class="built_in">NSTimeInterval</span>) duration;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)pause;</span><br><span class="line">- (<span class="keyword">void</span>)stop;</span><br><span class="line"><span class="comment">/* This method can't be called before the audio recorder stoped */</span></span><br><span class="line">- (<span class="built_in">BOOL</span>)deleteRecording;</span><br></pre></td></tr></table></figure><h4 id="Audio-Level-Metering"><a href="#Audio-Level-Metering" class="headerlink" title="Audio Level Metering"></a>Audio Level Metering</h4><p>Like AVAudioPlayer, the metering is not enabled by default.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">@property</span>(<span class="keyword">getter</span>=isMeteringEnabled) <span class="built_in">BOOL</span> meteringEnabled;</span><br><span class="line">- (<span class="keyword">void</span>)updateMeters;</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">float</span>)peakPowerForChannel:(<span class="built_in">NSUInteger</span>)channelNumber;</span><br><span class="line">- (<span class="keyword">float</span>)averagePowerForChannel:(<span class="built_in">NSUInteger</span>)channelNumber;</span><br></pre></td></tr></table></figure><h4 id="Handle-Interruption"><a href="#Handle-Interruption" class="headerlink" title="Handle Interruption"></a>Handle Interruption</h4><p>Pause the recording by your audio session got interrupted.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">[[<span class="built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="keyword">self</span> </span><br><span class="line">                                        selector:<span class="keyword">@selector</span>(handleInterruption:) </span><br><span class="line">                                            name:<span class="built_in">AVAudioSessionInterruptionNotification</span> </span><br><span class="line">                                          object:<span class="literal">nil</span>];</span><br><span class="line">                                          </span><br><span class="line">- (<span class="keyword">void</span>)handleInterruption:(<span class="built_in">NSNotification</span> *)notification &#123;</span><br><span class="line">    <span class="built_in">AVAudioSessionInterruptionType</span> type = [notification.userInfo[<span class="built_in">AVAudioSessionInterruptionTypeKey</span>] unsignedIntegerValue];</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (type == <span class="built_in">AVAudioSessionInterruptionTypeBegan</span>) &#123;</span><br><span class="line">        [<span class="keyword">self</span>.recorder pause];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Audio-file-Saving-and-deleting"><a href="#Audio-file-Saving-and-deleting" class="headerlink" title="Audio file Saving and deleting"></a>Audio file Saving and deleting</h4><p><code>AVAudioRecorder</code> needs a place to store the recording audio file. It is a good practice that store the audio file in the temporary directory in iOS file system during recording, and then copy the file to documents directory for permanent saving.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Create temperary url */</span></span><br><span class="line"><span class="built_in">NSString</span> *tmpPath = <span class="built_in">NSTemporaryDirectory</span>();</span><br><span class="line">tmpPath = [tmpPath stringByAppendingPathComponent:<span class="string">@"record.caf"</span>];</span><br><span class="line"><span class="built_in">NSURL</span> *tmpURL = [<span class="built_in">NSURL</span> fileURLWithPath:tmpPath];</span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* When saving the audio */</span></span><br><span class="line"><span class="comment">// create destination url for audio file</span></span><br><span class="line"><span class="comment">// use timestamp to be the unique id</span></span><br><span class="line"><span class="built_in">NSTimeInterval</span> timestamp = [<span class="built_in">NSDate</span> timeIntervalSinceRefernceDate];</span><br><span class="line"><span class="built_in">NSString</span> *fileName = [<span class="built_in">NSString</span> stringWithFormat:<span class="string">@"%@-%f.caf"</span>, audioName, timestamp];</span><br><span class="line"></span><br><span class="line"><span class="comment">// get documents directory path</span></span><br><span class="line"><span class="built_in">NSStirng</span> *docPath = [<span class="built_in">NSSearchPathForDirectoriesInDomains</span>(<span class="built_in">NSDocumentDirectory</span>, <span class="built_in">NSUserDomainMask</span>, <span class="literal">YES</span>) objectAtIndex:<span class="number">0</span>];</span><br><span class="line"><span class="built_in">NSString</span> *destPath = [docPath stringByAppendingPathComponent:fileName];</span><br><span class="line"><span class="built_in">NSURL</span> destURL = [<span class="built_in">NSURL</span> fileURLWithPath:destPath];</span><br><span class="line"></span><br><span class="line"><span class="comment">// use NSFileManager to copy the file</span></span><br><span class="line"><span class="built_in">NSError</span> *error;</span><br><span class="line"><span class="keyword">if</span> (![[<span class="built_in">NSFileManager</span> defaultManager] copyItemAtURL:tmpURL toURL:destURL error:&amp;error]）&#123;</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"%@"</span>, [error localizedDescription]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* delete audio file */</span></span><br><span class="line"><span class="built_in">NSError</span> *error;</span><br><span class="line"><span class="built_in">BOOL</span> success = [[<span class="built_in">NSFileManager</span> defaultManager] removeItemAtURL:audioFileURL error:&amp;error];</span><br><span class="line"><span class="keyword">if</span> (!success) &#123;</span><br><span class="line">     <span class="built_in">NSLog</span>(<span class="string">@"Unable to delete: %@"</span>, [error localizedDescription]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Test app is <a href="https://github.com/JasonHan1990/AVFoundation-Learning/tree/master/02-AVAudioRecorder" target="_blank" rel="noopener">Here</a>.</p><div class="figure center" style="width:;"><a class="fancybox" href="avaudiorecorder.png" title data-caption data-fancybox="default"><img class="fig-img" src="avaudiorecorder.png" alt></a></div><p><a href="https://developer.apple.com/av-foundation/" target="_blank" rel="noopener">AVFoundation Developer Guide</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;code&gt;AVAudioRecorder&lt;/code&gt; is also built on top of Audio Queue Services. It provides capability to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Record until user stop the recording&lt;/li&gt;
&lt;li&gt;Record for a specified duration&lt;/li&gt;
&lt;li&gt;Pause and resume recording&lt;/li&gt;
&lt;li&gt;Audio-level metering &lt;/li&gt;
&lt;/ul&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="AVFoundation" scheme="https://jasonhan1990.github.io/tags/AVFoundation/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="AVAudioPlayer" scheme="https://jasonhan1990.github.io/tags/AVAudioPlayer/"/>
    
  </entry>
  
  <entry>
    <title>AVAudioPlayer - AVFoundation</title>
    <link href="https://jasonhan1990.github.io/2017/08/15/avfoundation-avaudioplayer/"/>
    <id>https://jasonhan1990.github.io/2017/08/15/avfoundation-avaudioplayer/</id>
    <published>2017-08-15T21:03:50.000Z</published>
    <updated>2018-09-25T21:38:34.000Z</updated>
    
    <content type="html"><![CDATA[<p><code>AVAudioPlayer</code> makes easy to playback the audio data from local files and memory. It is built on top of Core Audio’s C-based Audio Queue Service. It provides all core functions we can find in Audio Queue Service.<br><a id="more"></a><br>Things that <code>AVAudioPlayer</code> can’t do:</p><ol><li>Play audio from a network stream</li><li>Access the raw audio sample</li><li>Require very low latency</li></ol><h4 id="Create-AVAudioPlayer"><a href="#Create-AVAudioPlayer" class="headerlink" title="Create AVAudioPlayer"></a>Create AVAudioPlayer</h4><p>The <code>AVAudioPlayer</code> can be created by <code>NSData</code> or <code>NSURL</code>.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Initializer for AVAudioPlayer</span></span><br><span class="line">- (<span class="keyword">nullable</span> <span class="keyword">instancetype</span>)initWithContentsOfURL:(<span class="built_in">NSURL</span> *)url error:(<span class="built_in">NSError</span> **)outError;</span><br><span class="line">- (<span class="keyword">nullable</span> <span class="keyword">instancetype</span>)initWithData:(<span class="built_in">NSData</span> *)data error:(<span class="built_in">NSError</span> **)outError;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Example: </span></span><br><span class="line"><span class="comment">// A function to create an AVAudioPlayer with local audio file name and its extension</span></span><br><span class="line">- (<span class="built_in">AVAudioPlayer</span> *)playerFileName:(<span class="built_in">NSString</span> *)name withExtension:(<span class="built_in">NSString</span> *)extension &#123;</span><br><span class="line">    <span class="built_in">NSURL</span> *fileURL = [[<span class="built_in">NSBundle</span> mainBundle] URLForResource:name withExtension:extension];</span><br><span class="line">    <span class="built_in">NSError</span> *err;</span><br><span class="line">    <span class="built_in">AVAudioPlayer</span> *player = [[<span class="built_in">AVAudioPlayer</span> alloc] initWithContentsOfURL:fileURL error:&amp;err];</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Configure the player</span></span><br><span class="line">    <span class="keyword">if</span> (player) &#123;</span><br><span class="line">        player.numberOfLoops = <span class="number">-1</span>; <span class="comment">// infinite loop</span></span><br><span class="line">        player.enableRate = <span class="literal">YES</span>;</span><br><span class="line">        [player prepareToPlay];</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@"%@"</span>, [err localizedDescription]);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> player;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Controlling-Playback"><a href="#Controlling-Playback" class="headerlink" title="Controlling Playback"></a>Controlling Playback</h4><p><code>AVAudioPlayer</code> provides ways for us to modify the player’s volume, panning, playback rate, number of looping and preform audio metering.<br>Calling <code>play()</code> will play a sound asynchronously. It will implicitly call the <code>prepareToPlay()</code> if the audio player is not already prepared to play. We can call the <code>prepareToPlay()</code> method after we created a audio player to minimize the lag between calling the <code>play()</code> method. Calling <code>stop()</code> method will stop the playback and undo the setup from <code>prepareToPlay()</code>.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* set the audio player’s stereo pan position, value from -1.0 to 1.0. A value of -1.0 is full left, 0.0 is center, 1.0 is full right. */</span></span><br><span class="line"><span class="keyword">@property</span> <span class="keyword">float</span> pan;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* set the audio player’s volume, value from 0.0 to 1.0. */</span></span><br><span class="line"><span class="keyword">@property</span> <span class="keyword">float</span> volume;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* set the audio player’s playback rate. Default value is 1.0, value 0.5 is half-speed playback, 2.0 is double-speed playback. To set playback rate, we need to enable rate adjustment. */</span></span><br><span class="line"><span class="keyword">@property</span> <span class="keyword">float</span> rate;</span><br><span class="line"><span class="comment">/* default is NO */</span></span><br><span class="line"><span class="keyword">@property</span> <span class="built_in">BOOL</span> enableRate;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* set number of times a sound will return to the beginning to repeat playback. Default value is 0, play once, a value of 1 plays twice, a negative value will play infinitely */</span></span><br><span class="line"><span class="keyword">@property</span> <span class="built_in">NSInteger</span> numberOfLoops;</span><br><span class="line"></span><br><span class="line">- (<span class="built_in">BOOL</span>)prepareToPlay;</span><br><span class="line">- (<span class="keyword">void</span>)play;</span><br><span class="line">- (<span class="built_in">BOOL</span>)playAtTime:(<span class="built_in">NSTimeInterval</span>)time;</span><br><span class="line">- (<span class="keyword">void</span>)pause;</span><br><span class="line">- (<span class="keyword">void</span>)stop;</span><br></pre></td></tr></table></figure><h4 id="Audio-Level-Metering"><a href="#Audio-Level-Metering" class="headerlink" title="Audio Level Metering"></a>Audio Level Metering</h4><p><code>AVAudioPlayer</code> doesn’t meter the audio-level by default. We can turn it on and get average sound decibel and peak decibel.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* default is not enabled */</span></span><br><span class="line"><span class="keyword">@property</span>(<span class="keyword">getter</span>=isMeteringEnabled) <span class="built_in">BOOL</span> meteringEnabled; </span><br><span class="line"></span><br><span class="line"><span class="comment">/* Refreshes the average and peak power values for all channels of an audio player. For best results, call this function in CADisplayLink */</span></span><br><span class="line">- (<span class="keyword">void</span>)updateMeters; </span><br><span class="line">- (<span class="keyword">float</span>)peakPowerForChannel:(<span class="built_in">NSUInteger</span>)channelNumber; </span><br><span class="line">- (<span class="keyword">float</span>)averagePowerForChannel:(<span class="built_in">NSUInteger</span>)channelNumber;</span><br></pre></td></tr></table></figure><h4 id="Configure-AVAudioSession"><a href="#Configure-AVAudioSession" class="headerlink" title="Configure AVAudioSession"></a>Configure AVAudioSession</h4><p>In order to make our app playback sound when we lock the screen or we turn our cellphones to silent mode, we need to choose the correct <code>AVAudioSessionCategory</code> to <code>AVAudioSession</code>.<br><code>AVAudioSession</code> is a global singleton instance. We can configure it after app launched. There are several categories. <a href="https://developer.apple.com/documentation/avfoundation/avaudiosession/audio_session_categories" target="_blank" rel="noopener">https://developer.apple.com/documentation/avfoundation/avaudiosession/audio_session_categories</a></p><table><thead><tr><th>Category</th><th>Allows Mixing</th><th>Audio Input</th><th>Audio Output</th><th>When Screen Lock</th><th>When Silent</th></tr></thead><tbody><tr><td>Ambient</td><td>yes</td><td>no</td><td>yes</td><td>off</td><td>off</td></tr><tr><td>Solo Ambient</td><td>no</td><td>no</td><td>yes</td><td>off</td><td>off</td></tr><tr><td>Playback</td><td>optional</td><td>no</td><td>yes</td><td>on</td><td>on</td></tr><tr><td>Record</td><td>no</td><td>yes</td><td>no</td><td>on</td><td>on</td></tr><tr><td>Play and Record</td><td>optional</td><td>yes</td><td>yes</td><td>on</td><td>on</td></tr><tr><td>Multi-Route</td><td>no</td><td>yes</td><td>yes</td><td>on</td><td>on</td></tr></tbody></table><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Configure AVAudioSession</span></span><br><span class="line"><span class="built_in">AVAudioSession</span> *session = [<span class="built_in">AVAudioSession</span> sharedInstance];</span><br><span class="line"></span><br><span class="line"><span class="built_in">NSError</span> *error;</span><br><span class="line"><span class="comment">// use AVAudioSessionCategoryPlayback to make the app playback sound when screen locked and silent turned on</span></span><br><span class="line"><span class="keyword">if</span> (![session setCategory:<span class="built_in">AVAudioSessionCategoryPlayback</span> error:&amp;error]) &#123;</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"Category Error: %@"</span>, [error localizedDescription]);</span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">if</span> (![session setActive:<span class="literal">YES</span> error:&amp;error]) &#123;</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"Activation Error: %@"</span>, [error localizedDescription]);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In order to make the app play in the background, we also need change the info.plist file. Add following code to the file.</p><figure class="highlight xml"><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"><span class="tag">&lt;<span class="name">key</span>&gt;</span>UIBackgroundModes<span class="tag">&lt;/<span class="name">key</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">array</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">string</span>&gt;</span>audio<span class="tag">&lt;/<span class="name">string</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">array</span>&gt;</span></span><br></pre></td></tr></table></figure><p>Adding this setting specifies that the application is now allowed to play audio in the background.</p><h4 id="Handle-Interruption"><a href="#Handle-Interruption" class="headerlink" title="Handle Interruption"></a>Handle Interruption</h4><p>When we got a call or alarm, our app will automatically pause the sound, but it will not play the sound after the interruption. We can listen the <code>AVAudioSessionInterruptionNotification</code> notification and code the behavior we want.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// add notification for audio player controller</span></span><br><span class="line">[[<span class="built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="keyword">self</span></span><br><span class="line">                                        selector:<span class="keyword">@selector</span>(handleInterruption:)</span><br><span class="line">                                           name:<span class="built_in">AVAudioSessionInterruptionNotification</span></span><br><span class="line">                                         object:[<span class="built_in">AVAudioSession</span> sharedInstance]];</span><br><span class="line">                                         </span><br><span class="line">- (<span class="keyword">void</span>)handleInterruption:(<span class="built_in">NSNotification</span> *)notification</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">AVAudioSessionInterruptionType</span> type = [notification.userInfo[<span class="built_in">AVAudioSessionInterruptionTypeKey</span>] unsignedIntegerValue];</span><br><span class="line">    <span class="keyword">if</span> (type == <span class="built_in">AVAudioSessionInterruptionTypeBegan</span>) &#123;</span><br><span class="line">        <span class="comment">// do something when interruption began</span></span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span> (type == <span class="built_in">AVAudioSessionInterruptionTypeEnded</span>) &#123;</span><br><span class="line">        <span class="comment">// do something when interruption ended</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="Handle-Route-Change"><a href="#Handle-Route-Change" class="headerlink" title="Handle Route Change"></a>Handle Route Change</h4><p>When we switch the audio output route, iOS will send a route change notification. Suppose we want to stop the playback when users unplug their headphone, we can check the notification’s userInfo dictionary for the route change reason and for a description of the previous audio route. If previous portType is <code>AVAudioSessionPortHeadphones</code>, we stop the playback.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Note This is not calling from main thread</span></span><br><span class="line">[[<span class="built_in">NSNotificationCenter</span> defaultCenter] addObserver:<span class="keyword">self</span></span><br><span class="line">                                        selector:<span class="keyword">@selector</span>(handleRouteChange:)</span><br><span class="line">                                            name:<span class="built_in">AVAudioSessionRouteChangeNotification</span></span><br><span class="line">                                          object:[<span class="built_in">AVAudioSession</span> sharedInstance]];</span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)handleRouteChange:(<span class="built_in">NSNotification</span> *)notification &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">AVAudioSessionRouteChangeReason</span> reason = [notification.userInfo[<span class="built_in">AVAudioSessionRouteChangeReasonKey</span>] unsignedIntegerValue];</span><br><span class="line">    <span class="keyword">if</span> (reason == <span class="built_in">AVAudioSessionRouteChangeReasonOldDeviceUnavailable</span>) &#123;</span><br><span class="line">        <span class="built_in">AVAudioSessionRouteDescription</span> *preRoute = notification.userInfo[<span class="built_in">AVAudioSessionRouteChangePreviousRouteKey</span>];</span><br><span class="line">        <span class="built_in">NSString</span> *portType = [[preRoute.outputs firstObject] portType];</span><br><span class="line">        <span class="keyword">if</span> ([portType isEqualToString:<span class="built_in">AVAudioSessionPortHeadphones</span>]) &#123;</span><br><span class="line">            <span class="comment">// stop the playback</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="AVAudioPlayer-Delegate"><a href="#AVAudioPlayer-Delegate" class="headerlink" title="AVAudioPlayer Delegate"></a>AVAudioPlayer Delegate</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Called when audioplayer finished playing.</span></span><br><span class="line">- (<span class="keyword">void</span>)audioPlayerDidFinishPlaying:(<span class="built_in">AVAudioPlayer</span> *)player successfully:(<span class="built_in">BOOL</span>)flag;</span><br><span class="line"><span class="comment">// Called when an audio player encounters a decoding error during playback.</span></span><br><span class="line">- (<span class="keyword">void</span>)audioPlayerDecodeErrorDidOccur:(<span class="built_in">AVAudioPlayer</span> *)player error:(<span class="built_in">NSError</span> *)error;</span><br></pre></td></tr></table></figure><p>Here is the link for the test app: <a href="https://github.com/JasonHan1990/AVFoundation-Learning/tree/master/01-AudioPlayer" target="_blank" rel="noopener">AVAudioPlayer Test App</a><br><div class="figure center" style="width:;"><a class="fancybox" href="Simulator-Screen-Shot.png" title="Screenshot" data-caption="Screenshot" data-fancybox="default"><img class="fig-img" src="Simulator-Screen-Shot.png" alt="Screenshot"></a><span class="caption">Screenshot</span></div></p><p><a href="https://developer.apple.com/av-foundation/" target="_blank" rel="noopener">AVFoundation Developer Guide</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;&lt;code&gt;AVAudioPlayer&lt;/code&gt; makes easy to playback the audio data from local files and memory. It is built on top of Core Audio’s C-based Audio Queue Service. It provides all core functions we can find in Audio Queue Service.&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="AVFoundation" scheme="https://jasonhan1990.github.io/tags/AVFoundation/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="AVAudioPlayer" scheme="https://jasonhan1990.github.io/tags/AVAudioPlayer/"/>
    
  </entry>
  
  <entry>
    <title>Swift Refreshing</title>
    <link href="https://jasonhan1990.github.io/2017/08/07/swift-refreshing/"/>
    <id>https://jasonhan1990.github.io/2017/08/07/swift-refreshing/</id>
    <published>2017-08-08T05:38:44.000Z</published>
    <updated>2018-09-23T04:37:27.000Z</updated>
    
    <content type="html"><![CDATA[<p>This is the note for swift knowledge refreshing.<br><a id="more"></a></p><h2 id="TYPES"><a href="#TYPES" class="headerlink" title="TYPES:"></a>TYPES:</h2><ol><li>All types are named with UpperCamelCase. All variables are named with lowerCamelCase.<ul><li>Types: <code>Bool</code>, <code>Int</code>, <code>String</code>, <code>Character</code>… or <code>MyType</code></li><li>Variables: num: Int, isTrue: Bool…</li></ul></li><li>Type conversion: <ul><li>type name(value): <code>Double(10)</code></li><li><code>as</code> keyword: <code>let doubleVal = 3 as Double</code></li></ul></li></ol><h2 id="TUPLES"><a href="#TUPLES" class="headerlink" title="TUPLES:"></a>TUPLES:</h2><p>When to use a tuple? For shortly operation, like sending multiple values to a function or return multiple values from a function. Otherwise, using struct or class.</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> coordinate: (<span class="type">Stirng</span>, <span class="type">Int</span>, <span class="type">Int</span>) = (<span class="string">"Coordinate"</span> , <span class="number">3</span>, <span class="number">5</span>)</span><br><span class="line"><span class="comment">// assign tuples</span></span><br><span class="line"><span class="keyword">var</span> (label, x, y) = coordinate</span><br><span class="line"><span class="comment">// use _ to disregard one value</span></span><br><span class="line"><span class="keyword">var</span> (<span class="number">_</span>, x, y) = coordinate</span><br><span class="line"></span><br><span class="line"><span class="comment">// access to the value in tuple</span></span><br><span class="line"><span class="keyword">let</span> coordinate: (<span class="type">Stirng</span>, <span class="type">Int</span>, <span class="type">Int</span>) = (<span class="string">"Coordinate"</span> , <span class="number">3</span>, <span class="number">5</span>)</span><br><span class="line"><span class="comment">// use index</span></span><br><span class="line">coordinate.<span class="number">0</span> <span class="comment">// "Coordinate"</span></span><br><span class="line">coordinate.<span class="number">1</span> <span class="comment">// 3</span></span><br><span class="line">coordinate.<span class="number">2</span> <span class="comment">// 5</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// or name the value</span></span><br><span class="line"><span class="keyword">let</span> coordinate_1 = (name: <span class="string">"Coordinate"</span>, x: <span class="number">3</span>, y: <span class="number">4</span>)</span><br><span class="line"><span class="comment">// use name</span></span><br><span class="line">coordinate_1.name <span class="comment">// "Coordinate"</span></span><br><span class="line">coordinate_1.x <span class="comment">// 3</span></span><br><span class="line">coordinate_1.y <span class="comment">// 5</span></span><br></pre></td></tr></table></figure><h2 id="LOOP"><a href="#LOOP" class="headerlink" title="LOOP:"></a>LOOP:</h2><figure class="highlight swift"><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"><span class="keyword">var</span> <span class="built_in">count</span> = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// while loop</span></span><br><span class="line"><span class="comment">// print: 0...3</span></span><br><span class="line"><span class="keyword">while</span> <span class="built_in">count</span> &lt; <span class="number">4</span> &#123;</span><br><span class="line">  connt += <span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">count</span> = <span class="number">0</span></span><br><span class="line"><span class="comment">// repeat while</span></span><br><span class="line"><span class="comment">// print: 1</span></span><br><span class="line"><span class="keyword">repeat</span> &#123;</span><br><span class="line">  <span class="built_in">count</span> += <span class="number">1</span></span><br><span class="line">&#125; <span class="keyword">while</span> <span class="built_in">count</span> &gt; <span class="number">100</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// for loop</span></span><br><span class="line"><span class="keyword">for</span> index <span class="keyword">in</span> <span class="number">0</span>..&lt;<span class="number">4</span> &#123;</span><br><span class="line">  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// skip one loop </span></span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// leave the loop</span></span><br><span class="line"><span class="keyword">break</span></span><br></pre></td></tr></table></figure><h2 id="SWITCHING"><a href="#SWITCHING" class="headerlink" title="SWITCHING:"></a>SWITCHING:</h2><figure class="highlight swift"><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"><span class="comment">// if you want to fall through the switch case, use fallthrough keyword</span></span><br><span class="line"><span class="keyword">switch</span> variable &#123;</span><br><span class="line">  <span class="keyword">case</span> value:</span><br><span class="line">    <span class="comment">// case code</span></span><br><span class="line">    <span class="keyword">fallthrough</span></span><br><span class="line">  <span class="keyword">default</span>:</span><br><span class="line">    <span class="comment">// default code</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// case can be a range</span></span><br><span class="line"><span class="keyword">let</span> choosed = <span class="number">2</span></span><br><span class="line"><span class="keyword">switch</span> choosed &#123;</span><br><span class="line">  <span class="keyword">case</span> <span class="number">0</span>...<span class="number">3</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">"You choosed a value between 0 to 3"</span>)</span><br><span class="line">  <span class="keyword">default</span>:</span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// case can be multiple value</span></span><br><span class="line"><span class="keyword">let</span> name = <span class="string">"Jason"</span></span><br><span class="line"><span class="keyword">switch</span> name &#123;</span><br><span class="line">  <span class="keyword">case</span> <span class="string">"Jason"</span>, <span class="string">"John"</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">"You meet Jason and John."</span>)</span><br><span class="line">  <span class="keyword">default</span>:</span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// tuple can use swich statement</span></span><br><span class="line"><span class="keyword">let</span> north = <span class="number">0</span>, south = <span class="number">1</span>, east = <span class="number">2</span>, west = <span class="number">3</span></span><br><span class="line"><span class="keyword">let</span> movement = (north, <span class="number">100</span>)</span><br><span class="line"><span class="keyword">switch</span> movement &#123;</span><br><span class="line">  <span class="keyword">case</span> (south, <span class="number">_</span>):</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">"You move to south."</span>)</span><br><span class="line">  <span class="keyword">case</span> (<span class="number">_</span>, <span class="number">100</span>):</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">"You move at 100 miles per hour."</span>)</span><br><span class="line">  <span class="keyword">default</span>:</span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// tuple case can be variables</span></span><br><span class="line"><span class="keyword">switch</span> movement &#123;</span><br><span class="line">  <span class="keyword">case</span> <span class="keyword">let</span> (direction, speed) <span class="keyword">where</span> speed &gt;= <span class="number">100</span>:</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">"You are overspeed."</span>)</span><br><span class="line">  <span class="keyword">default</span>:</span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="DICTIONARY"><a href="#DICTIONARY" class="headerlink" title="DICTIONARY:"></a>DICTIONARY:</h2><ul><li>Dictionary return optional.</li><li>Assign nil to delete key pair.</li><li>Iterate the dictionary<ul><li>for (key, value) in dictionary {}</li><li>for key in dictionary.keys {}</li><li>for val in dictionary.values {}</li></ul></li></ul><h2 id="STRUCTURE"><a href="#STRUCTURE" class="headerlink" title="STRUCTURE:"></a>STRUCTURE:</h2><p>By default, methods in struct can’t mutate the internal variables, because the struct is immutable. But we can label the method to mutating to do the job.</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">doSomethingToInternalVal</span><span class="params">()</span></span> &#123;</span><br><span class="line">  <span class="comment">// do something</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Properties:</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">TV</span> </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> height: <span class="type">Double</span></span><br><span class="line">  <span class="keyword">var</span> width: <span class="type">Double</span></span><br><span class="line">  <span class="keyword">var</span> diagonals: <span class="type">Int</span> &#123;</span><br><span class="line">    <span class="comment">// calculated here</span></span><br><span class="line">    <span class="keyword">return</span> result</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">var</span> spaceTaken: <span class="type">Double</span> &#123;</span><br><span class="line">    <span class="keyword">get</span> &#123;</span><br><span class="line">      <span class="comment">// calculate here</span></span><br><span class="line">      <span class="keyword">return</span> result</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">set</span> &#123;</span><br><span class="line">      height = <span class="type">Double</span>(newValue)</span><br><span class="line">    &#125;  </span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>properties: height and width. These can be accessed and mutated.</li><li>computed properties: diagnonal. These are read only.</li><li>getter and setter: get and set keywords in a computed property. For setter, we have a newValue keyword to get the setting value.</li><li>type properties: static properties. We don’t need a instance to get this property, just call the type and reference the property.</li></ul><h2 id="CLASS"><a href="#CLASS" class="headerlink" title="CLASS:"></a>CLASS:</h2><p>When we created an object with “let”, we assigned a constant reference to that variable. You can not assign a new object to it, but you can still change its properties.</p><p>Class need initializer when at least one of its properties is not initialed or nil.</p><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Compiler error: Class 'Address' has no initializers</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Address</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> street: <span class="type">String</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// you can solve by these ways</span></span><br><span class="line"><span class="comment">// add a init function</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Address</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> street: <span class="type">String</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">init</span>(street: <span class="type">String</span>) &#123;</span><br><span class="line">      <span class="keyword">self</span>.street = street</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// init the street by default</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Address</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> street: <span class="type">String</span> = <span class="string">""</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// set street to optional</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Address</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> street: <span class="type">String</span>?</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="INHERITANCE"><a href="#INHERITANCE" class="headerlink" title="INHERITANCE:"></a>INHERITANCE:</h2><p><code>final</code> keyword can prevent one class or function been inherited.</p><h2 id="INITIALIZERS"><a href="#INITIALIZERS" class="headerlink" title="INITIALIZERS:"></a>INITIALIZERS:</h2><ul><li>Designated initializer need to make sure all none optional properties has a value.</li><li>Convenience initializer must call designated initializer, however you can set some default values for some properties.<br>When calling parent’s initializer, we use <code>super.init()</code>. In swift, we call parent’s initializer after we init all properties in child’s class. This prevents a property been used before it is ready. And more important, we can only call the parent’s designated initializer but not convenience initializer.</li></ul><h2 id="PROTOCOL"><a href="#PROTOCOL" class="headerlink" title="PROTOCOL:"></a>PROTOCOL:</h2><blockquote><p>Property Requirements</p></blockquote><p>A protocol can require any confirming type to provide an instance property or type property. It only specifies the required property name and type and also specifies whether each property must be gettable or gettable and settable.</p><figure class="highlight swift"><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"><span class="class"><span class="keyword">protocol</span> <span class="title">SomeProtocol</span> </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> mustBeSettable: <span class="type">Int</span> &#123; <span class="keyword">get</span> <span class="keyword">set</span> &#125;</span><br><span class="line">  <span class="keyword">var</span> doesNotNeedToBeSettable: <span class="type">Int</span> &#123; <span class="keyword">get</span> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Always prefix type property requirements with the <code>static</code> keyword when you define them in protocol. </p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">protocol</span> <span class="title">AnotherProtocol</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">var</span> someTypeProperty: <span class="type">Int</span> &#123; <span class="keyword">get</span> <span class="keyword">set</span> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>Method Requirements</p></blockquote><p>Always prefix type method requirements with the static keyword when you define them in protocol. </p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">protocol</span> <span class="title">SomeProtocol</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="function"><span class="keyword">func</span> <span class="title">someTypeMethod</span><span class="params">()</span></span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Always prefix mutating method requirements with the mutating keyword when you define them in protocol to indicate that method is allowed to modify the instance it belongs and to any properties of that instance.</p><p>When a class confirmed the protocol with mutating method, we don’t need to put <code>mutating</code> keyword before the <code>func</code>. The mutating keyword is only used by structures and enumerations.</p><figure class="highlight swift"><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"><span class="class"><span class="keyword">protocol</span> <span class="title">Togglable</span> </span>&#123;</span><br><span class="line">  <span class="keyword">mutating</span> toggle()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">LightSwitch</span>: <span class="title">Togglable</span> </span>&#123;</span><br><span class="line">  <span class="keyword">case</span> on, off</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">mutating</span> toggle() &#123;</span><br><span class="line">    <span class="keyword">switch</span> <span class="keyword">self</span> &#123;</span><br><span class="line">      <span class="keyword">case</span> .on:</span><br><span class="line">        <span class="keyword">self</span> = .off</span><br><span class="line">      <span class="keyword">case</span> .off:</span><br><span class="line">        <span class="keyword">self</span> = .on</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Protocol can require specified initializer to be implemented by confirming types. When confirming types implement the initializer, put <code>required</code> keyword before <code>init</code>. If a subclass overrides a designated initializer from a superclass, and also implements a matching initializer requirement from a protocol, mark the initializer implementation with both the required and override modifiers.</p><figure class="highlight swift"><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"><span class="class"><span class="keyword">protocol</span> <span class="title">SomeProtocal</span> </span>&#123;</span><br><span class="line">  <span class="keyword">init</span>()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SomeSuperClass</span> </span>&#123;</span><br><span class="line">  <span class="keyword">init</span>() &#123;</span><br><span class="line">    <span class="comment">// init implementation</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SomeSubClass</span>: <span class="title">SomeSuperClass</span>, <span class="title">SomeProtocol</span> </span>&#123;</span><br><span class="line">  <span class="comment">// "required" from SomeProtocol conformance; "override" from SomeSuperClass</span></span><br><span class="line">  <span class="keyword">required</span> <span class="keyword">override</span> <span class="keyword">init</span>() &#123;</span><br><span class="line">    </span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>Protocol as type</p></blockquote><ol><li>As a parameter type or return type in a function, method, or initializer</li><li>As the type of a constant, variable, or property</li><li>As the type of items in an array, dictionary, or other container</li></ol><blockquote><p>Delegation:</p></blockquote><p>Delegation is a design pattern that enable a class or structure to hand off some of its responsibilities to an instance of another type. The delegation pattern is implemented by:</p><ol><li>Define an protocol which contains all delegated responsibilities.</li><li>A type confirms the protocol to guarantee to provide all delegated responsibilities.</li></ol><p>Delegation can respond to a particular action, or retrive data from an external source without understanding the type of the source. </p><blockquote><p>Protocol Inheritance:</p></blockquote><p>Protocol can inherit one or more other protocols and add further requirements.</p><blockquote><p>Class-only Protocol</p></blockquote><p>We can limit the protocol adoption to class type by adding class keyword after colon.</p><blockquote><p>Optional requirements</p></blockquote><p>Both the protocol and the optional requirement must be marked with the <code>@objc</code> attribute.<br>Note that <code>@objc</code> protocols can be adopted only by classes that inherit from Objective-C classes or other <code>@objc</code> classes.</p><figure class="highlight swift"><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"><span class="meta">@objc</span> <span class="class"><span class="keyword">protocol</span> <span class="title">CounterDataSource</span> </span>&#123;</span><br><span class="line">    <span class="meta">@objc</span> <span class="keyword">optional</span> <span class="function"><span class="keyword">func</span> <span class="title">increment</span><span class="params">(forCount <span class="built_in">count</span>: Int)</span></span> -&gt; <span class="type">Int</span></span><br><span class="line">    <span class="meta">@objc</span> <span class="keyword">optional</span> <span class="keyword">var</span> fixedIncrement: <span class="type">Int</span> &#123; <span class="keyword">get</span> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="CUSTOM-OPERATORS"><a href="#CUSTOM-OPERATORS" class="headerlink" title="CUSTOM OPERATORS:"></a>CUSTOM OPERATORS:</h2><blockquote><p>Overloading an existing operator: To overloading an operator, define a new function for the operator symbol.</p></blockquote><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Use * to repeat a string a specified number of times</span></span><br><span class="line"><span class="comment">// use extension to set what type of variable can use this operator</span></span><br><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">String</span> </span>&#123;</span><br><span class="line">  <span class="keyword">static</span> <span class="function"><span class="keyword">func</span> *<span class="params">(lhs: String, rhs: Int)</span></span> -&gt; <span class="type">String</span> &#123;</span><br><span class="line">    <span class="keyword">guard</span> rhs &gt; <span class="number">0</span> <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="string">""</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> res = <span class="keyword">left</span></span><br><span class="line">    <span class="keyword">for</span> <span class="number">_</span> <span class="keyword">in</span> <span class="number">0</span>..&lt;<span class="keyword">right</span> - <span class="number">1</span> &#123;</span><br><span class="line">      res += <span class="keyword">left</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="string">"a"</span> * <span class="number">6</span></span><br><span class="line"><span class="comment">// "aaaaaa"</span></span><br></pre></td></tr></table></figure><blockquote><p>Custom a new operator: A custom operator needs three things.</p></blockquote><ol><li>Define its precedence</li><li>Define its associativity: left, right or none. </li><li>Define whether its prefix, in fix or postfix</li></ol><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// create exponential operator **</span></span><br><span class="line"><span class="comment">// custom precedence group</span></span><br><span class="line">precedencegroup <span class="type">ExponentiationPrecedence</span> &#123;</span><br><span class="line">  higherThan: <span class="type">MultiplcationPrecedence</span></span><br><span class="line">  <span class="keyword">associativity</span>: <span class="keyword">none</span> <span class="comment">// none make the programmer use parenthsis</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// define the operator</span></span><br><span class="line"><span class="keyword">infix</span> <span class="keyword">operator</span> **: <span class="type">ExponentiationPrecedence</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// function</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> **<span class="params">(base: Double, exponent: Double)</span></span> -&gt; <span class="type">Double</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> pow(base, exponent)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="GENERICS"><a href="#GENERICS" class="headerlink" title="GENERICS"></a>GENERICS</h2><blockquote><p>Define generics:</p></blockquote><p>To make your function or type to be generic, add placeholder type name inside angle brackets.</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// example</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">swapTwoValues</span>&lt;T&gt;<span class="params">(<span class="number">_</span> a: <span class="keyword">inout</span> T, <span class="number">_</span> b: <span class="keyword">inout</span> T)</span></span>&#123;</span><br><span class="line">  <span class="keyword">let</span> temp = a</span><br><span class="line">  a = b</span><br><span class="line">  b = temp</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Stack</span>&lt;<span class="title">Element</span>&gt; </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> store = [<span class="type">Element</span>]()</span><br><span class="line">  <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">push</span><span class="params">(<span class="number">_</span> item: Element)</span></span> &#123;</span><br><span class="line">    store.append(item)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">pop</span><span class="params">()</span></span> &#123;</span><br><span class="line">    store.removeLast()</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> stackOfInt = <span class="type">Stack</span>&lt;<span class="type">Int</span>&gt;()</span><br><span class="line">stackOfInt.push(<span class="number">1</span>)</span><br></pre></td></tr></table></figure><blockquote><p>Extending a generic type</p></blockquote><p>When we extend a generic type, we don’t need to provide the type parameter in extension definition.</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// follow by the generic stack</span></span><br><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">Stack</span> </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> topItem: <span class="type">Element</span>? &#123;</span><br><span class="line">    <span class="keyword">return</span> store.last</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>Type constraint syntax</p></blockquote><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">someFunction</span>&lt;T: SomeClass, U: SomeProtocol&gt;<span class="params">(someT: T, someU: U)</span></span> &#123;</span><br><span class="line">  <span class="comment">// function body</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Example: we have a function which finds the index number for a generic item in an array.</p><figure class="highlight swift"><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"><span class="function"><span class="keyword">func</span> <span class="title">findIndex</span>&lt;T&gt;<span class="params">(of valueToFind: T, <span class="keyword">in</span> array:[T])</span></span> -&gt; <span class="type">Int</span>? &#123;</span><br><span class="line">    <span class="keyword">for</span> (index, value) <span class="keyword">in</span> array.enumerated() &#123;</span><br><span class="line">        <span class="keyword">if</span> value == valueToFind &#123;</span><br><span class="line">            <span class="keyword">return</span> index</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>We will see one error in the console, because not every Swift type confirmed the protocol Equatable.</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">error: binary <span class="keyword">operator</span> '==' cannot be applied to two '<span class="type">T'</span> operands</span><br></pre></td></tr></table></figure><p>To solve this problem, we can make a constraint to the generic type T by adding portable Equatable after <code>T:</code>. </p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">findIndex</span>&lt;T: Equatable&gt;<span class="params">(of valueToFind: T, <span class="keyword">in</span> array:[T])</span></span> -&gt; <span class="type">Int</span>? &#123;</span><br><span class="line">    <span class="comment">// same as above</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>If you want your custom types to use this function, you should make your custom types confirm the protocol Equatable. For example, we make a full name structure, and we have an array of names, find one in it.</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// make a FullName structure confirming Equatable protocol</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">FullName</span>: <span class="title">Equatable</span> </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> firstName: <span class="type">String</span></span><br><span class="line">    <span class="keyword">var</span> lastName: <span class="type">String</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">// Implement the equatable requirement</span></span><br><span class="line">    <span class="keyword">static</span> <span class="function"><span class="keyword">func</span> ==<span class="params">(lhs: FullName, rhs: FullName)</span></span> -&gt; <span class="type">Bool</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> lhs.firstName == rhs.firstName &amp;&amp; lhs.lastName == rhs.lastName</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// test</span></span><br><span class="line"><span class="keyword">let</span> n0 = <span class="type">FullName</span>(firstName: <span class="string">"Jason"</span>, lastName: <span class="string">"Han"</span>)</span><br><span class="line"><span class="keyword">let</span> n1 = <span class="type">FullName</span>(firstName: <span class="string">"Dane"</span>, lastName: <span class="string">"Fox"</span>)</span><br><span class="line"><span class="keyword">let</span> n2 = <span class="type">FullName</span>(firstName: <span class="string">"Billy"</span>, lastName: <span class="string">"Douglas"</span>)</span><br><span class="line"><span class="keyword">let</span> n3 = <span class="type">FullName</span>(firstName: <span class="string">"Fran"</span>, lastName: <span class="string">"Deleon"</span>)</span><br><span class="line"><span class="keyword">let</span> n4 = <span class="type">FullName</span>(firstName: <span class="string">"Carolina"</span>, lastName: <span class="string">"Buchanan"</span>)</span><br><span class="line"><span class="keyword">let</span> n5 = <span class="type">FullName</span>(firstName: <span class="string">"Natalee"</span>, lastName: <span class="string">"Howe"</span>)</span><br><span class="line"><span class="keyword">let</span> names: [<span class="type">FullName</span>] = [n0, n1, n2, n3, n4, n5]</span><br><span class="line"></span><br><span class="line">findIndex(of: <span class="type">FullName</span>(firstName: <span class="string">"Billy"</span>, lastName: <span class="string">"Douglas"</span>), <span class="keyword">in</span>: names)</span><br><span class="line"><span class="comment">// output: 2</span></span><br></pre></td></tr></table></figure><p>We can also use <code>where</code> clause to define constraints for type.</p><figure class="highlight swift"><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 class="comment">// The code above</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">findIndex</span>&lt;T: Equatable&gt;<span class="params">(of valueToFind: T, <span class="keyword">in</span> array:[T])</span></span> -&gt; <span class="type">Int</span>? &#123;</span><br><span class="line">    <span class="comment">// same as above</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// This can be written as</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">findIndex</span>&lt;T&gt;<span class="params">(of valueToFind: T, <span class="keyword">in</span> array:[T])</span></span> -&gt; <span class="type">Int</span>? <span class="keyword">where</span> <span class="type">T</span>: <span class="type">Equatable</span> &#123;</span><br><span class="line">    <span class="comment">// same as above</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>Associated Types</p></blockquote><p>An associated type gives a placeholder name to a type that is used as part of the protocol. Assign actual type to that associated type when the protocol is adopted. <code>associatedtype</code> keyword.</p><figure class="highlight swift"><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"><span class="comment">// Example we made an associated type Item in protocol container</span></span><br><span class="line"><span class="class"><span class="keyword">protocol</span> <span class="title">Container</span> </span>&#123;</span><br><span class="line">  associatedtype <span class="type">Item</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">(<span class="number">_</span> item: Item)</span></span></span><br><span class="line">  <span class="keyword">var</span> <span class="built_in">count</span>: <span class="type">Int</span> &#123; <span class="keyword">get</span> &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">subscript</span>(i: <span class="type">Int</span>) -&gt; <span class="type">Item</span> &#123; <span class="keyword">get</span> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// For a nongeneric type IntStack, we need define the type of Item in IntStack with typealias.</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">IntStack</span>: <span class="title">Container</span> </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> items = [<span class="type">Int</span>]()</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Let Swift know the type of Item</span></span><br><span class="line">  <span class="keyword">typealias</span> <span class="type">Item</span> = <span class="type">Int</span></span><br><span class="line">  </span><br><span class="line">  <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">(<span class="number">_</span> item: Int)</span></span> &#123;</span><br><span class="line">    items.append(item)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">var</span> <span class="built_in">count</span>: <span class="type">Int</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> items.<span class="built_in">count</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">subscript</span>(i: <span class="type">Int</span>) -&gt; <span class="type">Int</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> items[i]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// For a generic type Stack, Swift is smart enough to know the type of the Item.</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Stack</span>&lt;<span class="title">Element</span>&gt;: <span class="title">Container</span> </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> elements = [<span class="type">Element</span>]()</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">mutating</span> <span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">(<span class="number">_</span> item: Element)</span></span> &#123;</span><br><span class="line">        elements.append(item)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">  <span class="keyword">var</span> <span class="built_in">count</span>: <span class="type">Int</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> elements.<span class="built_in">count</span></span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">subscript</span>(i: <span class="type">Int</span>) -&gt; <span class="type">Element</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> elements[i]</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>More for the where clauses we talked above, it can do more jobs for type constraints. This is a function for checking two containers are equal.</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">allItemsMatch</span>&lt;C1: Container, C2: Container&gt;</span></span><br><span class="line"><span class="function">    <span class="params">(<span class="number">_</span> someContainer: C1, <span class="number">_</span> anotherContainer: C2)</span></span> -&gt; <span class="type">Bool</span></span><br><span class="line">    <span class="keyword">where</span> <span class="type">C1</span>.<span class="type">Item</span> == <span class="type">C2</span>.<span class="type">Item</span>, <span class="type">C1</span>.<span class="type">Item</span>: <span class="type">Equatable</span> &#123;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// Check that both containers contain the same number of items.</span></span><br><span class="line">        <span class="keyword">if</span> someContainer.<span class="built_in">count</span> != anotherContainer.<span class="built_in">count</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// Check each pair of items to see if they are equivalent.</span></span><br><span class="line">        <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">0</span>..&lt;someContainer.<span class="built_in">count</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> someContainer[i] != anotherContainer[i] &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// All items match, so return true.</span></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>In the where clauses:</p><ol><li><code>C1.Item == C2.Item</code> makes sure C1 and C2 contains same type of item.</li><li><code>C1.Item: Equatable</code> makes sure C1’s item confirming equatable protocol, also C2’s item since we checked two containers has same type of items.</li></ol><blockquote><p>Extension with generic where clause</p></blockquote><p>We can use extension with generic where clause to require the element to confirm to  a protocol and also require the element to be specific type.</p><figure class="highlight swift"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Use stack we create above</span></span><br><span class="line"><span class="comment">// We add a function to check whether an element is at the top of stack</span></span><br><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">Stack</span> <span class="title">where</span> <span class="title">Element</span>: <span class="title">Equatable</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">func</span> <span class="title">isTop</span><span class="params">(<span class="number">_</span> element: Element)</span></span> -&gt; <span class="type">Bool</span> &#123;</span><br><span class="line">    <span class="keyword">guard</span> <span class="keyword">let</span> topElement = store.last <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> topElement == element</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// We can specify the element to be double, and calculate the average number of all elements</span></span><br><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">Stack</span> <span class="title">where</span> <span class="title">Element</span> == <span class="title">Double</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">func</span> <span class="title">average</span><span class="params">()</span></span> -&gt; <span class="type">Double</span> &#123;</span><br><span class="line">    <span class="keyword">var</span> sum = <span class="number">0.0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="number">0</span>..&lt;store.<span class="built_in">count</span> &#123;</span><br><span class="line">      sum += store[i]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> sum / <span class="type">Double</span>(store.<span class="built_in">count</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="SUBSCRIPTS"><a href="#SUBSCRIPTS" class="headerlink" title="SUBSCRIPTS:"></a>SUBSCRIPTS:</h2><p>Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence.</p><figure class="highlight swift"><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 class="comment">// Example syntax</span></span><br><span class="line"><span class="keyword">subscript</span>(index: <span class="type">Int</span>) -&gt; <span class="type">Int</span> &#123;</span><br><span class="line">    <span class="keyword">get</span> &#123;</span><br><span class="line">        <span class="comment">// return an appropriate subscript value here</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">set</span>(newValue) &#123;</span><br><span class="line">        <span class="comment">// perform a suitable setting action here</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>For usage, we use [] after the type. Take dictionary as a example,</p><figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> numberOfPages = [<span class="string">"The Lord of the Rings"</span> : <span class="number">900</span>, <span class="string">"The Man Without Qualities"</span> : <span class="number">289</span>]</span><br><span class="line">numberOfPages[<span class="string">"The Man Without Qualities"</span>]</span><br><span class="line"><span class="comment">// print 289</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;This is the note for swift knowledge refreshing.&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="Swift" scheme="https://jasonhan1990.github.io/tags/Swift/"/>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
  </entry>
  
  <entry>
    <title>NSTimer</title>
    <link href="https://jasonhan1990.github.io/2016/11/23/nstimer/"/>
    <id>https://jasonhan1990.github.io/2016/11/23/nstimer/</id>
    <published>2016-11-24T06:09:17.000Z</published>
    <updated>2018-09-21T05:32:58.000Z</updated>
    
    <content type="html"><![CDATA[<p>I will talk about NSTimer in this order.</p><ol><li>Initial a NSTimer</li><li>Invalidate a NSTimer</li><li>NSTimer and runloop</li></ol><a id="more"></a><h2 id="Initial"><a href="#Initial" class="headerlink" title="Initial"></a>Initial</h2><p>To initial a NSTimer, apple offers three ways.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+ (<span class="built_in">NSTimer</span> *)scheduledTimerWithTimeInterval:(<span class="built_in">NSTimeInterval</span>)ti target:(<span class="keyword">id</span>)aTarget selector:(SEL)aSelector userInfo:(<span class="keyword">id</span>)userInfo repeats:(<span class="built_in">BOOL</span>)rep;</span><br></pre></td></tr></table></figure><p>This method creates a timer and schedules it on the current run loop in default mode. The concept of the run loop is pretty important in NSTimer. I will talk about it later.</p><hr><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">+ (<span class="built_in">NSTimer</span> *)timerWithTimeInterval:(<span class="built_in">NSTimeInterval</span>)ti target:(<span class="keyword">id</span>)aTarget selector:(SEL)aSelector userInfo:(<span class="keyword">id</span>)userInfo repeats:(<span class="built_in">BOOL</span>)rep;</span><br></pre></td></tr></table></figure><p>Compared with the first method, this one creates a timer without scheduling it on the run loop. But NSTimer only works when it is on a run loop. So, in order to make it work, we need to add it to a run loop by calling the <code>addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode</code> from NSRunloop.</p><hr><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">instancetype</span>)initWithFireDate:(<span class="built_in">NSDate</span> *)date interval:(<span class="built_in">NSTimeInterval</span>)ti target:(<span class="keyword">id</span>)t selector:(SEL)aSelector userInfo:(<span class="keyword">id</span>)ui repeats:(<span class="built_in">BOOL</span>)rep;</span><br></pre></td></tr></table></figure><p>Like the second method, this one does schedule the timer on a run loop, but it offers a way to create a fire date for the timer. Don’t forget to add the timer to a run loop by <code>addTimer: forMode:</code>.<br><div class="figure center" style="width:;"><a class="fancybox" href="n1-1.png" title="Difference between three ways" data-caption="Difference between three ways" data-fancybox="default"><img class="fig-img" src="n1-1.png" alt="Difference between three ways"></a><span class="caption">Difference between three ways</span></div></p><h2 id="Invalidate"><a href="#Invalidate" class="headerlink" title="Invalidate"></a>Invalidate</h2><p>Before taking about invalidate a NSTimer, let’s us see fire method first. </p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)fire;</span><br></pre></td></tr></table></figure><p>This method fires a repeating timer without interrupting its regular firing schedule. If the timer is non-repeating, it is automatically invalidated after firing, even if its scheduled fire date has not arrived. </p><p>Even if you didn’t put the timer on the run loop, you can use fire method to cause the receiver’s message to be sent to its target.</p><p>For example, with a non-repeated timer, after firing the timer, it will be invalidated. So, you can not fire it again.</p><div class="figure center" style="width:;"><a class="fancybox" href="n1-2.png" title="A non-repeated timer" data-caption="A non-repeated timer" data-fancybox="default"><img class="fig-img" src="n1-2.png" alt="A non-repeated timer"></a><span class="caption">A non-repeated timer</span></div><p>The NSLog:</p><div class="figure center" style="width:;"><a class="fancybox" href="n1-3.png" title="NSLog" data-caption="NSLog" data-fancybox="default"><img class="fig-img" src="n1-3.png" alt="NSLog"></a><span class="caption">NSLog</span></div><p>Then, with a repeated timer:</p><div class="figure center" style="width:;"><a class="fancybox" href="n1-4.png" title="A repeated timer" data-caption="A repeated timer" data-fancybox="default"><img class="fig-img" src="n1-4.png" alt="A repeated timer"></a><span class="caption">A repeated timer</span></div><p>The NSLog:</p><div class="figure center" style="width:;"><a class="fancybox" href="n1-5.png" title="NSLog" data-caption="NSLog" data-fancybox="default"><img class="fig-img" src="n1-5.png" alt="NSLog"></a><span class="caption">NSLog</span></div><hr><p>Now, let’s talk about invalidate.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (<span class="keyword">void</span>)invalidate;</span><br></pre></td></tr></table></figure><p>This method is the only way to remove a timer from an NSRunLoop object. Unlike other objects in OC, it is useless to set a timer to nil and let it be destroyed by ARC. The reason is not only the viewController has a strong reference to the timer, but the run loop also has one. When you set _timer = nil, you only break the reference between viewController and timer.</p><p>We can simply check the retain count by:</p><div class="figure center" style="width:;"><a class="fancybox" href="n1-6.png" title="Check retain count" data-caption="Check retain count" data-fancybox="default"><img class="fig-img" src="n1-6.png" alt="Check retain count"></a><span class="caption">Check retain count</span></div><p>The NSLog:<br><div class="figure center" style="width:;"><a class="fancybox" href="n1-7.png" title="NSLog" data-caption="NSLog" data-fancybox="default"><img class="fig-img" src="n1-7.png" alt="NSLog"></a><span class="caption">NSLog</span></div></p><p>So, to destroy a NSTimer, we usually do:</p><figure class="highlight objc"><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">[_timer invalidate];</span><br><span class="line">_timer = <span class="literal">nil</span>;</span><br></pre></td></tr></table></figure><p>and do this before the view is destroyed, not in -(void)deallocNSTimer andrunloop</p><p>What is the run loop? A run loop is an abstraction that (among other things) provides a mechanism to handle system input sources (sockets, ports, files, keyboard, touch, timers, etc). </p><p>NSTimer must be on a run loop, otherwise, it will not work.  By default, NSTimer will be scheduled on run loop with NSDefaultRunLoopMode. There are other modes such as UITrackingRunLoopMode. The problem is when you scroll a scrollView, the timer will stop until the scrolling is over, because the the run loop is working on the UITrackingRunLoopMode, all events on NSDefaultRunLoopMode will stop and wait.</p><p>To solve this problem, we can manually add a timer on all common modes. Notice that UITrackingRunLoopMode is also in common modes.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[[<span class="built_in">NSRunLoop</span> currentRunLoop] addTimer:_timer forMode:<span class="built_in">NSRunLoopCommonModes</span>];</span><br></pre></td></tr></table></figure><p>This will guarantee that timer will work, no matter what mode the current run loop is.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;I will talk about NSTimer in this order.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Initial a NSTimer&lt;/li&gt;
&lt;li&gt;Invalidate a NSTimer&lt;/li&gt;
&lt;li&gt;NSTimer and runloop&lt;/li&gt;
&lt;/ol&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="NSTimer" scheme="https://jasonhan1990.github.io/tags/NSTimer/"/>
    
  </entry>
  
  <entry>
    <title>Create Thumbnail For Video</title>
    <link href="https://jasonhan1990.github.io/2016/11/08/create-thumbnail-for-video/"/>
    <id>https://jasonhan1990.github.io/2016/11/08/create-thumbnail-for-video/</id>
    <published>2016-11-09T00:18:05.000Z</published>
    <updated>2018-09-21T00:23:58.000Z</updated>
    
    <content type="html"><![CDATA[<p>Here is how to create thumbnail for videos. Two steps:<br><a id="more"></a></p><ol><li>Use <code>AVURLAsset</code> to access to the video file by URL. Then use <code>AVAssetImageGenerator</code> to generate an image of one frame.</li><li>To distinguish the image we generated from normal images, add a play icon on the top of the image by merging two UIImage .</li></ol><p>Code:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><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></pre></td><td class="code"><pre><span class="line">+ (<span class="built_in">UIImage</span> *)createVideoThumbnailWithPath:(<span class="built_in">NSString</span> *)videoPath &#123;</span><br><span class="line">    <span class="keyword">if</span> (!videoPath)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nil</span>;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">AVURLAsset</span> *asset = [[<span class="built_in">AVURLAsset</span> alloc] initWithURL:[<span class="built_in">NSURL</span> fileURLWithPath:videoPath] options:<span class="literal">nil</span>];</span><br><span class="line">    <span class="built_in">AVAssetImageGenerator</span> *imgGenerator = [[<span class="built_in">AVAssetImageGenerator</span> alloc] initWithAsset:asset];</span><br><span class="line">    imgGenerator.appliesPreferredTrackTransform = <span class="literal">YES</span>;</span><br><span class="line">    imgGenerator.apertureMode = <span class="built_in">AVAssetImageGeneratorApertureModeEncodedPixels</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// create CGImage</span></span><br><span class="line">    <span class="built_in">CGImageRef</span> thumbnailImgRef = <span class="literal">nil</span>;</span><br><span class="line">    <span class="comment">// the time frame</span></span><br><span class="line">    <span class="built_in">CFTimeInterval</span> thumbnailImageTime = <span class="number">0</span>;</span><br><span class="line">    <span class="built_in">NSError</span> *error = <span class="literal">nil</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// get the image</span></span><br><span class="line">    thumbnailImgRef = [imgGenerator copyCGImageAtTime:<span class="built_in">CMTimeMake</span>(thumbnailImageTime, <span class="number">60</span>) actualTime:<span class="literal">nil</span> error:&amp;error];</span><br><span class="line"></span><br><span class="line">    <span class="comment">// error handling</span></span><br><span class="line">    <span class="keyword">if</span> (!thumbnailImgRef)</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@"VIDEO THUMBNAIL ERROR: %@"</span>, error);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// convert to UIImage</span></span><br><span class="line">    <span class="built_in">UIImage</span> *image = thumbnailImgRef ? [[<span class="built_in">UIImage</span> alloc] initWithCGImage:thumbnailImgRef] : <span class="literal">nil</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// add playIcon</span></span><br><span class="line">    <span class="keyword">if</span> (image) &#123;</span><br><span class="line">        <span class="comment">// grab your play icon</span></span><br><span class="line">        <span class="built_in">UIImage</span> *playIcon = [<span class="built_in">UIImage</span> imageNamed:<span class="string">@"PlayIcon"</span>];</span><br><span class="line"></span><br><span class="line">        <span class="comment">// start image context</span></span><br><span class="line">        <span class="built_in">UIGraphicsBeginImageContext</span>(image.size);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// add original image first with existing opacity</span></span><br><span class="line">        [image drawInRect:<span class="built_in">CGRectMake</span>(<span class="number">0</span>,<span class="number">0</span>,image.size.width,image.size.height)];</span><br><span class="line"></span><br><span class="line">        <span class="comment">// add play icon over the image in the middle with supplied opacity if applicable</span></span><br><span class="line">        [playIcon drawInRect:<span class="built_in">CGRectMake</span>((image.size.width - playIcon.size.width) / <span class="number">2.0</span>,</span><br><span class="line">                                        (image.size.height - playIcon.size.height) / <span class="number">2.0</span>,</span><br><span class="line">                                        playIcon.size.width,playIcon.size.height)</span><br><span class="line">                   blendMode:kCGBlendModeNormal</span><br><span class="line">                       alpha:<span class="number">0.9</span>];</span><br><span class="line"></span><br><span class="line">        <span class="comment">// get merged image</span></span><br><span class="line">        <span class="built_in">UIImage</span> *newImage = <span class="built_in">UIGraphicsGetImageFromCurrentImageContext</span>();</span><br><span class="line"></span><br><span class="line">        <span class="built_in">UIGraphicsEndImageContext</span>();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> newImage;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> image;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Here is how to create thumbnail for videos. Two steps:&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="Code Snippet" scheme="https://jasonhan1990.github.io/tags/Code-Snippet/"/>
    
  </entry>
  
  <entry>
    <title>Error: Cannot Assign To &#39;self&#39; Outside Of A Method In The Init Family</title>
    <link href="https://jasonhan1990.github.io/2016/11/03/error-record-1/"/>
    <id>https://jasonhan1990.github.io/2016/11/03/error-record-1/</id>
    <published>2016-11-03T22:37:06.000Z</published>
    <updated>2018-09-21T00:23:37.000Z</updated>
    
    <content type="html"><![CDATA[<p>I got this error because I mistyped the <strong>Link</strong> to <strong>link</strong>.<br><a id="more"></a><br><div class="figure center" style="width:;"><a class="fancybox" href="e1-1.png" title data-caption data-fancybox="default"><img class="fig-img" src="e1-1.png" alt></a></div></p><p>So two rules that Xcode determine a method is an init method:</p><ol><li>return <code>instancetype</code> or <code>id</code></li><li>the method name should be a capital letter followed by <code>init</code>. </li></ol><p>For example:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">- (intancetype)initWithImage:(<span class="built_in">UIImage</span> *)image;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;I got this error because I mistyped the &lt;strong&gt;Link&lt;/strong&gt; to &lt;strong&gt;link&lt;/strong&gt;.&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="Error" scheme="https://jasonhan1990.github.io/tags/Error/"/>
    
  </entry>
  
  <entry>
    <title>GCD Note 2</title>
    <link href="https://jasonhan1990.github.io/2016/10/31/gcd-note-2/"/>
    <id>https://jasonhan1990.github.io/2016/10/31/gcd-note-2/</id>
    <published>2016-10-31T22:14:07.000Z</published>
    <updated>2018-09-21T00:22:35.000Z</updated>
    
    <content type="html"><![CDATA[<p>Continue after <a href="/2018/09/19/gcd-note-1">GCD Note 1</a>.<br><a id="more"></a></p><h2 id="dispatch-after"><a href="#dispatch-after" class="headerlink" title="dispatch_after"></a>dispatch_after</h2><p>The method dispatch_after works like a delayed dispatch_async. The dispatch_after() function submits the block to the given queue at the time specified by the when parameter.</p><p>Example:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, <span class="number">2</span> * <span class="built_in">NSEC_PER_SEC</span>);</span><br><span class="line">dispatch_after(delay, dispatch_get_main_queue(), ^&#123;</span><br><span class="line">   <span class="comment">//do something on main thread after 2 sec</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="dispatch-group"><a href="#dispatch-group" class="headerlink" title="dispatch group"></a>dispatch group</h2><p>Dispatch group is used to do some updates after a group of tasks. The tasks in the group can be either asynchronous or synchronous. To create a group:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dispatch_group_t group = dispatch_group_create();</span><br></pre></td></tr></table></figure><p>There are two ways to add tasks to the group. The first way is adding a block of code to the group, and executing on a specified queue like globe queue:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">dispatch_group_async(group,specifiedQueue,^&#123;</span><br><span class="line">    <span class="comment">// do something 1 here</span></span><br><span class="line">&#125;);</span><br><span class="line">dispatch_group_async(group,specifiedQueue,^&#123;</span><br><span class="line">    <span class="comment">// do something 2 here</span></span><br><span class="line">&#125;);</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>But this is not suitable for something you want to have callback straight away. </p><p>The second way is to set starting and ending manually by using <code>dispatch_group_enter()</code> and <code>dispatch_group_leaving()</code>.</p><p>Suppose we need to download an image with its thumbnail and the original image from a server with different URLs.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><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">dispatch_group_t group = dispatch_group_create();</span><br><span class="line"><span class="keyword">for</span> (<span class="built_in">NSInteger</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span>; i++) &#123;</span><br><span class="line">    <span class="built_in">NSURL</span> *url;</span><br><span class="line">    <span class="keyword">switch</span> (i) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">0</span>:</span><br><span class="line">              url = [<span class="built_in">NSURL</span> URLWithString:thumbnailURLString];</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line">              url = [<span class="built_in">NSURL</span> URLWithString:orignalURLString];</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">     &#125;</span><br><span class="line">    dispatch_group_enter(group);</span><br><span class="line">    <span class="built_in">UIImage</span> *image = [ImageDownloader alloc] initWithURL: url withCompletion:^(<span class="built_in">NSError</span> *error) &#123;</span><br><span class="line">        <span class="keyword">if</span> (error) &#123;</span><br><span class="line">            <span class="comment">// handle the error</span></span><br><span class="line">        &#125;</span><br><span class="line">        dispatch_grounp_leave(group);</span><br><span class="line">    &#125;];</span><br><span class="line"></span><br><span class="line">    <span class="comment">// store the images some where</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Notice that the number of enter should be equal to the number of leave. </p><p>Then, how to notify that the group is finished. There are also two ways. First one, using <code>dispatch_group_wait()</code>.</p><figure class="highlight objc"><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">dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);</span><br><span class="line"><span class="comment">// do something after group is finished</span></span><br></pre></td></tr></table></figure><p>This method will return a long value if the time expired before all tasks are finished, and it will block the current thread.</p><p>The second way is to use <code>dispatch_group_notify()</code>:</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">dispatch_group_notify(dispatch_group_t group, specifiedQueue,^&#123;</span><br><span class="line">    <span class="comment">// do something here on the specifiedQueue</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>The <code>dispatch_group_notify()</code> function provides asynchronous notification of the completion of the blocks associated with the group by submitting the block to the specified queue once all blocks associated with the group have completed.</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Continue after &lt;a href=&quot;/2018/09/19/gcd-note-1&quot;&gt;GCD Note 1&lt;/a&gt;.&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/tags/iOS/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="GCD" scheme="https://jasonhan1990.github.io/tags/GCD/"/>
    
  </entry>
  
  <entry>
    <title>Why strongSelf and weakSelf?</title>
    <link href="https://jasonhan1990.github.io/2016/10/25/strong-weak-self/"/>
    <id>https://jasonhan1990.github.io/2016/10/25/strong-weak-self/</id>
    <published>2016-10-26T02:51:16.000Z</published>
    <updated>2018-09-21T00:20:19.000Z</updated>
    
    <content type="html"><![CDATA[<p>Before talking about strongSelf and weakSelf, I need briefly explain retain cycle.<br><a id="more"></a><br>So, a retain cycle usually occurs when an object A has a strong reference to Object B, and Object B also has a strong reference to Object A. Under this situation, the retainCount for both objects can not be 0, so the memory for these two objects won’t be released. This is the memory leak. The retain cycle could happen between multiple objects as long as their references between each other form a cycle.<br><div class="figure center" style="width:;"><a class="fancybox" href="strong-weak-self-1.png" title="Retain cycle 1" data-caption="Retain cycle 1" data-fancybox="default"><img class="fig-img" src="strong-weak-self-1.png" alt="Retain cycle 1"></a><span class="caption">Retain cycle 1</span></div><br>Also, an object can have a reference of itself which will cause retain cycle too. The most common situation is that an object owns a block, and in the block, we call any of this object’s methods or properties. Then the block has a reference to this object itself, which cause a retain cycle. Notice that blocks maintain strong references to any captured objects, including self, because they don’t want data be destroyed by ARC before themselves getting executed.<br><div class="figure center" style="width:;"><a class="fancybox" href="strong-weak-self-2.png" title="Retain cycle 2" data-caption="Retain cycle 2" data-fancybox="default"><img class="fig-img" src="strong-weak-self-2.png" alt="Retain cycle 2"></a><span class="caption">Retain cycle 2</span></div></p><h4 id="Example-1"><a href="#Example-1" class="headerlink" title="Example 1:"></a>Example 1:</h4><p>I have an object called Car. Car has a block called drive.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// car.h</span></span><br><span class="line"><span class="meta">#import <span class="meta-string">&lt;Foundation/Foundation.h&gt;</span></span></span><br><span class="line"><span class="keyword">typedef</span> <span class="keyword">void</span>(^Drive)();</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">Car</span> : <span class="title">NSObject</span></span></span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">copy</span>) <span class="built_in">NSString</span> *miles;</span><br><span class="line"><span class="keyword">@property</span> (<span class="keyword">nonatomic</span>, <span class="keyword">copy</span>) Drive drive;</span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure><p>In the viewController.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#import <span class="meta-string">"ViewController.h"</span></span></span><br><span class="line"><span class="meta">#import <span class="meta-string">"Car.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">ViewController</span> ()</span></span><br><span class="line"><span class="keyword">@end</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">ViewController</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad &#123;</span><br><span class="line">    [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"></span><br><span class="line">    Car *car = [[Car alloc]init];</span><br><span class="line">    car.miles = <span class="string">@"100 miles"</span>;</span><br><span class="line"></span><br><span class="line">    car.drive = ^&#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@"Car drived %@"</span>, car.miles);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    car.drive();</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"return"</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure><p>Leak! Here, the car has a strong reference to the drive block, and in the block, the block has a strong reference to the car since we called car.miles. This made the car has a reference to itself.</p><p>Using Instruments to detect the leak. Click the red cross. Malloc 48 Bytes means the system allocate 48 Bytes of memory to the block.</p><div class="figure center" style="width:;"><a class="fancybox" href="strong-weak-self-3.png" title data-caption data-fancybox="default"><img class="fig-img" src="strong-weak-self-3.png" alt></a></div><p>Open Cycles &amp; Roots. You can see the cycle.</p><div class="figure center" style="width:;"><a class="fancybox" href="strong-weak-self-4.png" title="no ivar: Instruments can't find the variable name that allocated the memory so you get the [no ivar] message." data-caption="no ivar: Instruments can't find the variable name that allocated the memory so you get the [no ivar] message." data-fancybox="default"><img class="fig-img" src="strong-weak-self-4.png" alt="no ivar: Instruments can't find the variable name that allocated the memory so you get the [no ivar] message."></a><span class="caption">no ivar: Instruments can't find the variable name that allocated the memory so you get the [no ivar] message.</span></div><p>Change the Example 1 to Example 2.</p><h4 id="Example-2"><a href="#Example-2" class="headerlink" title="Example 2:"></a>Example 2:</h4><p>I pass a parameter into the block. Leak?</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#import <span class="meta-string">"ViewController.h"</span></span></span><br><span class="line"><span class="meta">#import <span class="meta-string">"Car.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">ViewController</span> ()</span></span><br><span class="line"><span class="keyword">@end</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">ViewController</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad &#123;</span><br><span class="line">    [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"></span><br><span class="line">    Car *car = [[Car alloc]init];</span><br><span class="line">    car.miles = <span class="string">@"100 miles"</span>;</span><br><span class="line"></span><br><span class="line">    car.drive = ^(<span class="built_in">NSString</span> *miles)&#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@"Car drived %@"</span>, miles);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    car.drive(car.miles);</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"return"</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure><p>No Leak. Checking the leak with instruments:</p><div class="figure center" style="width:;"><a class="fancybox" href="strong-weak-self-5.png" title data-caption data-fancybox="default"><img class="fig-img" src="strong-weak-self-5.png" alt></a></div><p>Since I pass the car.miles into the block as a parameter, and the block won’t retain the parameter, there will be no retain cycle.</p><h3 id="WEAKSELF-AND-STRONGSELF"><a href="#WEAKSELF-AND-STRONGSELF" class="headerlink" title="WEAKSELF AND STRONGSELF"></a>WEAKSELF AND STRONGSELF</h3><h4 id="weakSelf"><a href="#weakSelf" class="headerlink" title="weakSelf"></a>weakSelf</h4><p>How to create a weakSelf? There are two ways.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">__<span class="keyword">weak</span> __<span class="keyword">typeof</span>(<span class="keyword">self</span>) weakSelf = <span class="keyword">self</span>; </span><br><span class="line"><span class="comment">// Write this code every time before you use weakself.</span></span><br></pre></td></tr></table></figure><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#define WEAKSELF typeof(self) __ weak weakSelf = self  </span></span><br><span class="line"><span class="comment">// Or create a macro in header file, then you can use WEAKSELF everywhere.</span></span><br></pre></td></tr></table></figure><p>The reason we use weakSelf in a block is that with weak property, the block won’t retain the object in the block. Then we break the cycle. For example 1, we can use weakself to solve the retain cycle problem.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><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"><span class="meta">#import <span class="meta-string">"ViewController.h"</span></span></span><br><span class="line"><span class="meta">#import <span class="meta-string">"Car.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">ViewController</span> ()</span></span><br><span class="line"><span class="keyword">@end</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">ViewController</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad &#123;</span><br><span class="line">    [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"></span><br><span class="line">    Car *car = [[Car alloc]init];</span><br><span class="line">    car.miles = <span class="string">@"100 miles"</span>;</span><br><span class="line"></span><br><span class="line">    __<span class="keyword">weak</span> __<span class="keyword">typeof</span>(car) weakCar = car;</span><br><span class="line">    car.drive = ^&#123;</span><br><span class="line">        <span class="built_in">NSLog</span>(<span class="string">@"Car drived %@"</span>, weakCar.miles);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    car.drive();</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"return"</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure><h4 id="strongSelf"><a href="#strongSelf" class="headerlink" title="strongSelf"></a>strongSelf</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">__<span class="keyword">strong</span> __<span class="keyword">typeof</span>(weakSelf) strongSelf = weakSelf;</span><br></pre></td></tr></table></figure><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#define STRONGSELF typeof(weakSelf) __strong strongSelf = weakSelf</span></span><br></pre></td></tr></table></figure><p>Since we use weakSelf in the block to prevent the retain cycle problem, there is a potential problem that the object could be released before the block has been executed. </p><h4 id="example-3"><a href="#example-3" class="headerlink" title="example 3:"></a>example 3:</h4><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#import <span class="meta-string">"ViewController.h"</span></span></span><br><span class="line"><span class="meta">#import <span class="meta-string">"Car.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">ViewController</span> ()</span></span><br><span class="line"><span class="keyword">@end</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">ViewController</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad &#123;</span><br><span class="line">    [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"></span><br><span class="line">    Car *car = [[Car alloc]init];</span><br><span class="line">    car.miles = <span class="string">@"100 miles"</span>;</span><br><span class="line"></span><br><span class="line">    __<span class="keyword">weak</span> __<span class="keyword">typeof</span>(car) weakCar = car;</span><br><span class="line">    car.drive = ^&#123;</span><br><span class="line">        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<span class="number">2.0</span> * <span class="built_in">NSEC_PER_SEC</span>)), dispatch_get_main_queue(), ^&#123;</span><br><span class="line">            <span class="built_in">NSLog</span>(<span class="string">@"Car drived %@"</span>, weakCar.miles);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;;</span><br><span class="line">    car.drive();</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"return"</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure><p>I add a delay before executing the NSlog(). Then the output is:<br><code>... 15:28:20.875923 BlockTest[7630:4429580] return... 15:28:23.065725 BlockTest[7630:4429580] Car drived (null)</code></p><p>What is happening here? The dispatch_after() function submits the block (which contains NSLog()) to the given queue (Here is the main queue) at the time specified by the when (Here is after 2 sec) parameter. Think the block as a task. The dispatch_after() asynchronously add the task to the main queue after two sec when you execute the study block. Since the study block has a weak reference to the car, after the study block has been execute (car.drive() is called), the weakCar is released by ARC, then the weak object will be set as nil. However, the dispatch block is still not executed. That is why we got null in the output.</p><p>So, we add strongSelf in the block which prevent the object will not be released inside the block. After the block is executed, strongSelf then release.</p><figure class="highlight objc"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#import <span class="meta-string">"ViewController.h"</span></span></span><br><span class="line"><span class="meta">#import <span class="meta-string">"Car.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@interface</span> <span class="title">ViewController</span> ()</span></span><br><span class="line"><span class="keyword">@end</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">@implementation</span> <span class="title">ViewController</span></span></span><br><span class="line"></span><br><span class="line">- (<span class="keyword">void</span>)viewDidLoad &#123;</span><br><span class="line">    [<span class="keyword">super</span> viewDidLoad];</span><br><span class="line"></span><br><span class="line">    Car *car = [[Car alloc]init];</span><br><span class="line">    car.miles = <span class="string">@"100 miles"</span>;</span><br><span class="line"></span><br><span class="line">    __<span class="keyword">weak</span> __<span class="keyword">typeof</span>(car) weakCar = car;</span><br><span class="line">    car.drive = ^&#123;</span><br><span class="line">        __<span class="keyword">strong</span> __<span class="keyword">typeof</span>(weakCar) strongCar = weakCar;</span><br><span class="line">        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<span class="number">2.0</span> * <span class="built_in">NSEC_PER_SEC</span>)), dispatch_get_main_queue(), ^&#123;</span><br><span class="line">            <span class="built_in">NSLog</span>(<span class="string">@"Car drived %@"</span>, strongCar.miles);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    car.drive();</span><br><span class="line">    <span class="built_in">NSLog</span>(<span class="string">@"return"</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">@end</span></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;Before talking about strongSelf and weakSelf, I need briefly explain retain cycle.&lt;br&gt;
    
    </summary>
    
      <category term="iOS" scheme="https://jasonhan1990.github.io/categories/iOS/"/>
    
    
      <category term="iOS Animation" scheme="https://jasonhan1990.github.io/tags/iOS-Animation/"/>
    
      <category term="Objc" scheme="https://jasonhan1990.github.io/tags/Objc/"/>
    
      <category term="Memory Leak" scheme="https://jasonhan1990.github.io/tags/Memory-Leak/"/>
    
      <category term="Retain Cycle" scheme="https://jasonhan1990.github.io/tags/Retain-Cycle/"/>
    
  </entry>
  
</feed>
