<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[My Octopress Blog]]></title>
  <link href="http://IamAlchemist.github.io/atom.xml" rel="self"/>
  <link href="http://IamAlchemist.github.io/"/>
  <updated>2015-11-20T19:47:19+08:00</updated>
  <id>http://IamAlchemist.github.io/</id>
  <author>
    <name><![CDATA[Your Name]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[理解 Objective-C Runtime]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/11/19/understanding-the-objective-c-runtime/"/>
    <updated>2015-11-19T13:35:18+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/11/19/understanding-the-objective-c-runtime</id>
    <content type="html"><![CDATA[<p>Objective-C扩展了C语言，并加入了面向对象特性和Smalltalk式的消息传递机制。而这个扩展的核心是一个用C和汇编写的Runtime库。它负责加载类的信息，分发函数消息。从而使得c可以面向对象，变成了Objective-C。
Runtime的核心就是消息传递 (Messaging)</p>

<blockquote><p>I’m sorry that I long ago coined the term “objects” for this topic because it gets many people to focus on the lesser idea. <strong>The big idea is “messaging”</strong> – that is what the kernal[sic] of Smalltalk is all about&hellip; The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.</p></blockquote>

<p><em>&ndash; by Alan Kay</em></p>

<p> <!-- more --></p>

<p>在C语言调用一个方法其实就是跳到内存中的某一点并开始执行一段代码。没有任何动态的特性，因为这在编译时就决定好了。而在 Objective-C中，<code>[object foo]</code>语句并不会立即执行<code>foo</code>这个方法的代码。它是在运行时给<code>object</code>发送一条叫<code>foo</code>的消息。这个消息，也许会由<code>object</code>来处理，也许会被转发给另一个对象，或者不予理睬假装没收到这个消息。多条不同的消息也可以对应同一个方法实现。这些都是在程序运行的时候决定的。</p>

<p>事实上，在编译时Objective-C函数调用的语法都会被翻译成一个C的函数调用 - objc_msgSend().<br/>
比如，编译器会把</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="p">[</span><span class="n">target</span> <span class="nl">doMethodWith</span><span class="p">:</span><span class="n">var1</span><span class="p">];</span>
</span></code></pre></td></tr></table></div></figure>


<p>编译成</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="n">objc_msgSend</span><span class="p">(</span><span class="n">target</span><span class="p">,</span><span class="k">@selector</span><span class="p">(</span><span class="nl">doMethodWith</span><span class="p">:),</span><span class="n">var1</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>显然，发送消息并不是直接的函数调用，到objc_msgSend里面就是Objective-C Runtime来处理了。</p>

<h3>objc_object, objc_class 以及 Ojbc_method</h3>

<p>在Objective-C中，本质上，类、对象和方法都是一个C的结构体</p>

<p>比如我们知道<code>id</code>就是指向一个Objective-C的对象的指针，也就是<code>objc_object</code>的实例，其中有一个<code>isa</code>指针，这个<code>isa</code>指向它所属的类。来看看它的定义</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="k">typedef</span> <span class="k">struct</span> <span class="n">objc_object</span> <span class="p">{</span>
</span><span class='line'>    <span class="kt">Class</span> <span class="n">isa</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span> <span class="o">*</span><span class="kt">id</span><span class="p">;</span>
</span></code></pre></td></tr></table></div></figure>


<p>所以当你拿到一个<code>id</code>指针之后，就可以获取这个对象的类，并且可以检测其是否响应一个<code>selector</code>。isa指向的<code>objc_class</code>实例的里面其实保存的就是该对象对应的类的信息。定义如下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="k">typedef</span> <span class="k">struct</span> <span class="n">objc_class</span> <span class="o">*</span><span class="kt">Class</span><span class="p">;</span>
</span><span class='line'><span class="k">struct</span> <span class="n">objc_class</span> <span class="p">{</span>
</span><span class='line'>    <span class="kt">Class</span> <span class="n">isa</span><span class="p">;</span>
</span><span class='line'>    <span class="kt">Class</span> <span class="n">super_class</span><span class="p">;</span>
</span><span class='line'>    <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">;</span>
</span><span class='line'>    <span class="kt">long</span> <span class="n">instance_size</span><span class="p">;</span>
</span><span class='line'>    <span class="k">struct</span> <span class="n">objc_ivar_list</span> <span class="o">*</span><span class="n">ivars</span><span class="p">;</span>
</span><span class='line'>    <span class="k">struct</span> <span class="n">objc_method_list</span> <span class="o">**</span><span class="n">methodLists</span><span class="p">;</span>
</span><span class='line'>    <span class="k">struct</span> <span class="n">objc_cache</span> <span class="o">*</span><span class="n">cache</span><span class="p">;</span>
</span><span class='line'>    <span class="k">struct</span> <span class="n">objc_protocol_list</span> <span class="o">*</span><span class="n">protocols</span><span class="p">;</span>
</span><span class='line'><span class="p">};</span>
</span><span class='line'>
</span><span class='line'><span class="k">struct</span> <span class="n">objc_method_list</span> <span class="p">{</span>
</span><span class='line'>    <span class="k">struct</span> <span class="n">objc_method_list</span> <span class="o">*</span><span class="n">obsolete</span><span class="p">;</span>
</span><span class='line'>    <span class="kt">int</span> <span class="n">method_count</span><span class="p">;</span>
</span><span class='line'>    <span class="k">struct</span> <span class="n">objc_method</span> <span class="n">method_list</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<p>我们看到这些类的信息包括，继承关系，实现的协议，方法列表，和属性列表，实例大小，ivar的类型和布局等等。其中方法都对应结构体是<code>objc_method</code>，这个结构体其实就是一个key/value对，定义如下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="k">typedef</span> <span class="k">struct</span> <span class="n">objc_selector</span>  <span class="o">*</span><span class="kt">SEL</span><span class="p">;</span>
</span><span class='line'><span class="k">typedef</span> <span class="nf">id</span> <span class="p">(</span><span class="o">*</span><span class="kt">IMP</span><span class="p">)(</span><span class="kt">id</span> <span class="nb">self</span><span class="p">,</span><span class="kt">SEL</span> <span class="n">_cmd</span><span class="p">,...);</span>
</span><span class='line'><span class="k">struct</span> <span class="n">objc_method</span> <span class="p">{</span>
</span><span class='line'>    <span class="kt">SEL</span> <span class="n">method_name</span><span class="p">;</span>
</span><span class='line'>    <span class="kt">char</span> <span class="o">*</span><span class="n">method_types</span><span class="p">;</span>
</span><span class='line'>    <span class="kt">IMP</span> <span class="n">method_imp</span><span class="p">;</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<p>key是所谓的<code>Selector</code>(相当于编译器生成的唯一的标识函数的字符串)；而值就是<code>IMP</code>，一个<code>IMP</code>就是一个函数指针，由编译器生成的，当你发起一个消息之后，最终它会执行的那个代码，就是由这个函数指针指定的。</p>

<p>从这些定义中可以看出， 发送一条消息，也就是<code>objc_msgSend</code>，大概到底做了什么事情。</p>

<p>举<code>objc_msgSend(obj, foo)</code>这个例子来说：</p>

<ul>
<li>首先，通过 obj 的 isa 指针找到它的 class</li>
<li>在 class 的 method list 找 foo</li>
<li>如果 class 中没到 foo，继续往它的 superclass 中找</li>
<li>一旦找到 foo 这个函数，就去执行它的实现IMP</li>
</ul>


<p><code>block</code>的设计也类似，它也包含了isa的指针</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'>
</span><span class='line'><span class="k">struct</span> <span class="n">Block_literal_1</span> <span class="p">{</span>
</span><span class='line'>    <span class="kt">void</span> <span class="o">*</span><span class="n">isa</span><span class="p">;</span> <span class="c1">// initialized to &amp;_NSConcreteStackBlock or &amp;_NSConcreteGlobalBlock</span>
</span><span class='line'>  <span class="p">...</span>
</span><span class='line'><span class="p">};</span>
</span></code></pre></td></tr></table></div></figure>


<p>所以block像object一样也是可以响应消息的。</p>

<h3>MetaClass</h3>

<p><code>isa</code>指向对象就是该object对应的类。也就是Objective-C的类本身也是一个对象，暂时我们称之为类对象(class object)。 它包含的信息包括，继承关系，实现的协议，方法列表，和属性列表，实例大小，ivar的类型和布局等等。当你进行类方法(class method)的调用的时候的时候，比方说</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="p">[</span><span class="bp">NSObject</span> <span class="n">alloc</span><span class="p">];</span>
</span></code></pre></td></tr></table></div></figure>


<p>你事实上是把这个消息发给了这个类对象(class object)。</p>

<p>既然class object是一个实例，那么它必然是属于某一个类，这个类被称作metaclass。一个metaclass就是class object的描述，就像一个class是它的object的描述一样。</p>

<p>值得一提的是，metaclass的方法列表就是我们称之为class methods的东西：class本身应该响应的那些selectors。当你发送一个消息给class，也就是metaclass的实例的时候，objc_msgSend()会查找metaclass的方法列表（包括它的父类），来决定是否可以响应。一个class method记录在metaclass里，就像instance method记录在class中。</p>

<p>metaclass也是一个实例，也有父类，也有<code>isa</code>和<code>super_class</code>。最终的源头是一个特殊的root class。不过metaclass的<code>isa</code>指针其实是无关紧要的，因为现实中，没有人会给metaclass object发送消息的。 <br/>
相对更重要的是metaclass的继承关系，metaclass有着和class一样的平行的继承关系。所以class methods也就相应的有了继承关系。 <br/>
此外，由于root metaclass的父类是root class，所以每一个class object可以响应root class的instance methods<br/>
最后任何一个class object都是root class（或者它的子类的）实例</p>

<p>下面这张图能很好的总结上面的结论，始终要记住的是，当一个message发送给一个object的时候，这个object首先根据<code>isa</code>指针来寻找是否可以响应，然后在根据<code>super_class</code>指针在继承链中寻找</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-11-20.png" width="598"></p>

<h3>为啥我们要继承 Apple Classes</h3>

<p>初学Cocoa开发的时候，多数教程都要我们继承一个类比方NSObject，然后我们就开始Coding了。比方说：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="n">MyObject</span> <span class="o">*</span><span class="n">object</span> <span class="o">=</span> <span class="p">[[</span><span class="n">MyObject</span> <span class="n">alloc</span><span class="p">]</span> <span class="n">init</span><span class="p">];</span>
</span></code></pre></td></tr></table></div></figure>


<p>这个语句用来初始化一个实例，类似于 C++ 的 new 关键字。这个语句首先会执行MyObject这个类的+alloc方法，所以继承 Apple 的类我们不仅是获得了很多很好用的属性，而且也继承了这种内存分配的方法。</p>

<h3>什么是Class Cache(objc_cache *cache)</h3>

<p>每次发送一个消息的时候，都要去查找方法列表的实现有个问题，效率低。比如一个class往往只有20%的函数会被经常调用，可能占总调用次数的80%。每个消息都需要遍历一次<code>objc_method_list</code>并不合理。如果把经常被调用的函数缓存下来，那可以大大提高函数查询的效率。这也就是<code>objc_class</code>中另一个重要成员<code>objc_cache</code>做的事情 - 再找到foo之后，把foo的<code>method_name</code>作为key，<code>method_imp</code>作为value给存起来。当再次收到foo消息的时候，可以直接在cache里找到，避免去遍历<code>objc_method_list</code>.</p>

<h3>说回 objc_msgSend 这个方法</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="p">[</span><span class="nb">self</span> <span class="nl">printMessageWithString</span><span class="p">:</span><span class="s">@&quot;Hello World!&quot;</span><span class="p">];</span>
</span></code></pre></td></tr></table></div></figure>


<p>会被编译器翻译成</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="n">objc_msgSend</span><span class="p">(</span><span class="nb">self</span><span class="p">,</span><span class="k">@selector</span><span class="p">(</span><span class="nl">printMessageWithString</span><span class="p">:),</span><span class="s">@&quot;Hello World!&quot;</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>objc_msgSend执行的步骤大致是这样：</p>

<ul>
<li>检测这个selector是不是要忽略的。比如Mac OS X开发，有了垃圾回收就不理会retain,release这些消息了</li>
<li>检测这个target是不是<code>nil</code>。ObjC的特性是允许对一个<code>nil</code>对象执行任何一个方法不会Crash，因为会被忽略掉</li>
<li>如果上面两个都过了，那就开始查找这个类的IMP，先从cache里面找，找得到的话，就跳到对应的函数去执行</li>
<li>如果cache找不到就到成员方法列表里去找，还找不到，就到父类里去找</li>
<li>最后还找不到的话，就要进行消息转发逻辑</li>
</ul>


<h3>消息转发机制</h3>

<p>在上面的例子中，如果@selector(printMessageWithString:)最终没有找到，通常情况下，程序会在运行时挂掉并抛出<code>unrecognized selector sent to …</code>的异常。但在异常抛出前，Objective-C的运行时会给你三次拯救程序的机会：</p>

<ul>
<li><strong>Method resolution</strong></li>
<li><strong>Fast forwarding</strong></li>
<li><strong>Normal forwarding</strong></li>
</ul>


<h3>Method Resolution</h3>

<p>在找不到消息对应的函数后，首先，Objective-C运行时会调用+resolveInstanceMethod: 或者+resolveClassMethod:，让你有机会提供一个函数实现。如果你添加了函数并返回YES，那运行时系统就会重新启动一次消息发送的过程。以foo为例，你可以这么实现</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="kt">void</span> <span class="nf">fooMethod</span><span class="p">(</span><span class="kt">id</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">SEL</span> <span class="n">_cmd</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Doing foo&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="p">+</span> <span class="p">(</span><span class="kt">BOOL</span><span class="p">)</span><span class="nf">resolveInstanceMethod:</span><span class="p">(</span><span class="kt">SEL</span><span class="p">)</span><span class="nv">aSEL</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">if</span><span class="p">(</span><span class="n">aSEL</span> <span class="o">==</span> <span class="k">@selector</span><span class="p">(</span><span class="nl">foo</span><span class="p">:)){</span>
</span><span class='line'>        <span class="n">class_addMethod</span><span class="p">([</span><span class="nb">self</span> <span class="k">class</span><span class="p">],</span> <span class="n">aSEL</span><span class="p">,</span> <span class="p">(</span><span class="kt">IMP</span><span class="p">)</span><span class="n">fooMethod</span><span class="p">,</span> <span class="s">&quot;v@:&quot;</span><span class="p">);</span>
</span><span class='line'>        <span class="k">return</span> <span class="nb">YES</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">return</span> <span class="p">[</span><span class="nb">super</span> <span class="n">resolveInstanceMethod</span><span class="p">];</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Core Data有用到这个方法。NSManagedObjects中properties的getter和setter就是在运行时动态添加的</p>

<p>如果resolve方法返回NO，运行时就会移到下一步：消息转发（Message Forwarding）</p>

<p>PS：iOS 4.3 加入很多新的 runtime 方法，主要都是以 imp 为前缀的方法，比如 imp_implementationWithBlock() 用 block 快速创建一个 imp 。
上面的例子可以重写成：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="kt">IMP</span> <span class="n">fooIMP</span> <span class="o">=</span> <span class="n">imp_implementationWithBlock</span><span class="p">(</span><span class="o">^</span><span class="p">(</span><span class="kt">id</span> <span class="n">_self</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>    <span class="n">NSLog</span><span class="p">(</span><span class="s">@&quot;Doing foo&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="n">class_addMethod</span><span class="p">([</span><span class="nb">self</span> <span class="k">class</span><span class="p">],</span> <span class="n">aSEL</span><span class="p">,</span> <span class="n">fooIMP</span><span class="p">,</span> <span class="s">&quot;v@:&quot;</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Fast forwarding</h3>

<p>消息转发（Message Forwarding）首先会执行Fast forwarding，也就是如果目标对象实现了<code>-forwardingTargetForSelector:</code>，Runtime这时就会调用这个方法，给你把这个消息转发给其他对象的机会</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="p">-</span> <span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nf">forwardingTargetForSelector:</span><span class="p">(</span><span class="kt">SEL</span><span class="p">)</span><span class="nv">aSelector</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">if</span><span class="p">(</span><span class="n">aSelector</span> <span class="o">==</span> <span class="k">@selector</span><span class="p">(</span><span class="nl">foo</span><span class="p">:)){</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">alternateObject</span><span class="p">;</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">return</span> <span class="p">[</span><span class="nb">super</span> <span class="nl">forwardingTargetForSelector</span><span class="p">:</span><span class="n">aSelector</span><span class="p">];</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>只要这个方法返回的不是nil和self，整个消息发送的过程就会被重启，当然发送的对象会变成你返回的那个对象。否则，就会继续Normal Fowarding。</p>

<p>这里叫Fast，只是为了区别下一步的转发机制。因为这一步不会创建任何新的对象，但下一步转发会创建一个 NSInvocation 对象，所以相对更快点。</p>

<h3>Normal forwarding</h3>

<p>这一步是Runtime最后一次给你挽救的机会。首先它会发送<code>-methodSignatureForSelector:</code>消息获得函数的参数和返回值类型。如果<code>-methodSignatureForSelector:</code>返回nil，Runtime则会发出<code>-doesNotRecognizeSelector:</code>消息，程序这时也就挂掉了。如果返回了一个函数签名，Runtime就会创建一个<code>NSInvocation</code>对象并发送<code>-forwardInvocation:</code>消息给目标对象。</p>

<p>NSInvocation 实际上就是对一个消息的描述，包括selector 以及参数等信息。所以你可以在<code>-forwardInvocation:</code>里修改传进来的<code>NSInvocation</code>对象，然后发送<code>-invokeWithTarget:</code>消息给它，传进去一个新的目标：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='objc'><span class='line'><span class="p">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">forwardInvocation:</span><span class="p">(</span><span class="bp">NSInvocation</span> <span class="o">*</span><span class="p">)</span><span class="nv">invocation</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="kt">SEL</span> <span class="n">sel</span> <span class="o">=</span> <span class="n">invocation</span><span class="p">.</span><span class="n">selector</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span><span class="p">([</span><span class="n">alternateObject</span> <span class="nl">respondsToSelector</span><span class="p">:</span><span class="n">sel</span><span class="p">])</span> <span class="p">{</span>
</span><span class='line'>        <span class="p">[</span><span class="n">invocation</span> <span class="nl">invokeWithTarget</span><span class="p">:</span><span class="n">alternateObject</span><span class="p">];</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>    <span class="k">else</span> <span class="p">{</span>
</span><span class='line'>        <span class="p">[</span><span class="nb">self</span> <span class="nl">doesNotRecognizeSelector</span><span class="p">:</span><span class="n">sel</span><span class="p">];</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Cocoa 里很多地方都利用到了消息传递机制来对语言进行扩展，如 Proxies、NSUndoManager 跟 Responder Chain。NSProxy 就是专门用来作为代理转发消息的；NSUndoManager 截取一个消息之后再发送；而 Responder Chain 保证一个消息转发给合适的响应者。</p>

<p>Apple 设计这种机制的原因之一就是——用来模拟多重继承（ObjC 原生是不支持多重继承的）。或者把复杂设计隐藏起来。</p>

<h4>参考资料</h4>

<p><a href="http://cocoasamurai.blogspot.jp/2010/01/understanding-objective-c-runtime.html">Understanding the Objective-C Runtime</a></p>

<p><a href="http://tech.glowing.com/cn/objective-c-runtime/">Objective-C Runtime</a></p>

<p><a href="http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html">Classes and metaclasses</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[JNI基础介绍]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/09/18/basic-introduction-of-jni/"/>
    <updated>2015-09-18T14:57:30+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/09/18/basic-introduction-of-jni</id>
    <content type="html"><![CDATA[<p>这里简单介绍一下JNI的语法</p>

<p> <!-- more --></p>

<h4>初识第一面</h4>

<h5>HelloJNI.java</h5>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloJNI</span> <span class="o">{</span>
</span><span class='line'>   <span class="kd">static</span> <span class="o">{</span>
</span><span class='line'>      <span class="n">System</span><span class="o">.</span><span class="na">loadLibrary</span><span class="o">(</span><span class="s">&quot;hello&quot;</span><span class="o">);</span> <span class="c1">// Load native library at runtime</span>
</span><span class='line'>                                   <span class="c1">// hello.dll (Windows) or libhello.so (Unixes)</span>
</span><span class='line'>   <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Declare a native method sayHello() that receives nothing and returns void</span>
</span><span class='line'>   <span class="kd">private</span> <span class="kd">native</span> <span class="kt">void</span> <span class="nf">sayHello</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Test Driver</span>
</span><span class='line'>   <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>      <span class="k">new</span> <span class="nf">HelloJNI</span><span class="o">().</span><span class="na">sayHello</span><span class="o">();</span>  <span class="c1">// invoke the native method</span>
</span><span class='line'>   <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<h5>HelloJNI.h/.c</h5>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">JNIEXPORT</span> <span class="kt">void</span> <span class="n">JNICALL</span> <span class="nf">Java_HelloJNI_sayHello</span><span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;Hello World!</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">return</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>需要注意的有：</p>

<ul>
<li>函数命名约定 <code>Java_{package_and_classname}_{function_name}(JNI arguments)</code></li>
<li>JNIEnv*: 对于JNI环境的引用, 通过这个入口可以进行jni函数</li>
<li>jobject: 对于this对象的引用</li>
</ul>


<h4>JNI基础</h4>

<p>JNI在native系统中定义了下面这些JNI数据类型，来对应Java的类型。</p>

<ul>
<li>Java基本类型：jint，jbyte，jshort，jlong，jfloat，jdouble，jchar，jboolean对应Java的int，byte，short，long，float，double，char，boolean</li>
<li>Java应用类型：jobject对应java.lang.Object。同时还有一下子类型</li>
<li>jclass -> java.lang.Class</li>
<li>jstring -> java.lang.String</li>
<li>jthrowable -> java.lang.Throwable</li>
<li>jarray -> Java Array。也就是jintArray, jbyteArray, jshortArray, jlongArray, jfloatArray, jdoubleArray, jcharArray, jbooleanArray, jobjectArray.</li>
</ul>


<p>由于native的函数都是接受JNI类型参数，返回JNI类型参数，所以一般情况下我们需要这样做：</p>

<ul>
<li>把JNI的参数转换或者拷贝成C可以操作的类型，如jintArray到int[]</li>
<li>使用C类型参数完成计算</li>
<li>把结果转换或者拷贝成JNI类型并返回</li>
</ul>


<p>JNI环境提供了大量的这些转换工作的工具可以帮助大家完成</p>

<h4>在Java和Nativie之间传递参数</h4>

<h5>基础类型</h5>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'>    <span class="c1">// In &quot;win\jni_mh.h&quot; - machine header which is machine dependent</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="kt">long</span>            <span class="n">jint</span><span class="p">;</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="kr">__int64</span>         <span class="n">jlong</span><span class="p">;</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="kt">signed</span> <span class="kt">char</span>     <span class="n">jbyte</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="c1">// In &quot;jni.h&quot;</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="kt">unsigned</span> <span class="kt">char</span>   <span class="n">jboolean</span><span class="p">;</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="kt">unsigned</span> <span class="kt">short</span>  <span class="n">jchar</span><span class="p">;</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="kt">short</span>           <span class="n">jshort</span><span class="p">;</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="kt">float</span>           <span class="n">jfloat</span><span class="p">;</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="kt">double</span>          <span class="n">jdouble</span><span class="p">;</span>
</span><span class='line'>  <span class="k">typedef</span> <span class="n">jint</span>            <span class="n">jsize</span><span class="p">;</span>
</span></code></pre></td></tr></table></div></figure>


<h5>String</h5>

<p>JNI环境提供了函数可以进行很方便的转换</p>

<ul>
<li>jstring -> char* : <code>const char* GetStringUTFChars(JNIEnv*, jstring, jboolean*)</code>.</li>
<li>char* -> jstring : <code>jstring NewStringUTF(JNIEnv*, char*)</code>.</li>
</ul>


<p>例如：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">JNIEXPORT</span> <span class="n">jstring</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNIString_sayHello</span><span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">jstring</span> <span class="n">inJNIStr</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="c1">// Step 1: Convert the JNI String (jstring) into C-String (char*)</span>
</span><span class='line'>   <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">inCStr</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetStringUTFChars</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">inJNIStr</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">inCSt</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Step 2: Perform its intended operations</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, the received string is: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">inCStr</span><span class="p">);</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">ReleaseStringUTFChars</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">inJNIStr</span><span class="p">,</span> <span class="n">inCStr</span><span class="p">);</span>  <span class="c1">// release resources</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Prompt user for a C-string</span>
</span><span class='line'>   <span class="kt">char</span> <span class="n">outCStr</span><span class="p">[</span><span class="mi">128</span><span class="p">];</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;Enter a String: &quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="n">scanf</span><span class="p">(</span><span class="s">&quot;%s&quot;</span><span class="p">,</span> <span class="n">outCStr</span><span class="p">);</span>    <span class="c1">// not more than 127 characters</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Step 3: Convert the C-string (char*) into JNI String (jstring) and return</span>
</span><span class='line'>   <span class="k">return</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewStringUTF</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">outCStr</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h5>primitive数组</h5>

<ul>
<li>jintArray -> jint[], <code>jint* GetIntArrayElements(JNIEnv *env, jintArray a, jboolean *iscopy)</code>.</li>
<li>jint[] -> jintArray, 首先分配内存<code>jintArray NewIntArray(JNIEnv *env, jsize len)</code>, 然后填充<code>void SetIntArrayRegion(JNIEnv *env, jintArray a, jsize start, jsize len, const jint *buf)</code></li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">JNIEXPORT</span> <span class="n">jdoubleArray</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNIPrimitiveArray_sumAndAverage</span>
</span><span class='line'>          <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">jintArray</span> <span class="n">inJNIArray</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="c1">// Step 1: Convert the incoming JNI jintarray to C&#39;s jint[]</span>
</span><span class='line'>   <span class="n">jint</span> <span class="o">*</span><span class="n">inCArray</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetIntArrayElements</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">inJNIArray</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">inCArray</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>   <span class="n">jsize</span> <span class="n">length</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetArrayLength</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">inJNIArray</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Step 2: Perform its intended operations</span>
</span><span class='line'>   <span class="n">jint</span> <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>   <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
</span><span class='line'>   <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">length</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">sum</span> <span class="o">+=</span> <span class="n">inCArray</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
</span><span class='line'>   <span class="p">}</span>
</span><span class='line'>   <span class="n">jdouble</span> <span class="n">average</span> <span class="o">=</span> <span class="p">(</span><span class="n">jdouble</span><span class="p">)</span><span class="n">sum</span> <span class="o">/</span> <span class="n">length</span><span class="p">;</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">ReleaseIntArrayElements</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">inJNIArray</span><span class="p">,</span> <span class="n">inCArray</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// release resources</span>
</span><span class='line'>
</span><span class='line'>   <span class="n">jdouble</span> <span class="n">outCArray</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="n">sum</span><span class="p">,</span> <span class="n">average</span><span class="p">};</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Step 3: Convert the C&#39;s Native jdouble[] to JNI jdoublearray, and return</span>
</span><span class='line'>   <span class="n">jdoubleArray</span> <span class="n">outJNIArray</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewDoubleArray</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>  <span class="c1">// allocate</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">outJNIArray</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">SetDoubleArrayRegion</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">outJNIArray</span><span class="p">,</span> <span class="mi">0</span> <span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">outCArray</span><span class="p">);</span>  <span class="c1">// copy</span>
</span><span class='line'>   <span class="k">return</span> <span class="n">outJNIArray</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h5>访问对象变量并且调用Java方法</h5>

<p><em>访问实例对象</em></p>

<ul>
<li>GetObjectID</li>
<li>GetFieldID</li>
<li>GetInt</li>
<li>SetFieldID</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">JNIEXPORT</span> <span class="kt">void</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNIInstanceVariable_modifyInstanceVariable</span>
</span><span class='line'>          <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="c1">// Get a reference to this object&#39;s class</span>
</span><span class='line'>   <span class="n">jclass</span> <span class="n">thisClass</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetObjectClass</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// int</span>
</span><span class='line'>   <span class="c1">// Get the Field ID of the instance variables &quot;number&quot;</span>
</span><span class='line'>   <span class="n">jfieldID</span> <span class="n">fidNumber</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetFieldID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisClass</span><span class="p">,</span> <span class="s">&quot;number&quot;</span><span class="p">,</span> <span class="s">&quot;I&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">fidNumber</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get the int given the Field ID</span>
</span><span class='line'>   <span class="n">jint</span> <span class="n">number</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetIntField</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">fidNumber</span><span class="p">);</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, the int is %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Change the variable</span>
</span><span class='line'>   <span class="n">number</span> <span class="o">=</span> <span class="mi">99</span><span class="p">;</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">SetIntField</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">fidNumber</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get the Field ID of the instance variables &quot;message&quot;</span>
</span><span class='line'>   <span class="n">jfieldID</span> <span class="n">fidMessage</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetFieldID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisClass</span><span class="p">,</span> <span class="s">&quot;message&quot;</span><span class="p">,</span> <span class="s">&quot;Ljava/lang/String;&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">fidMessage</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// String</span>
</span><span class='line'>   <span class="c1">// Get the object given the Field ID</span>
</span><span class='line'>   <span class="n">jstring</span> <span class="n">message</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetObjectField</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">fidMessage</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Create a C-string with the JNI String</span>
</span><span class='line'>   <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">cStr</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetStringUTFChars</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">cStr</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, the string is %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">cStr</span><span class="p">);</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">ReleaseStringUTFChars</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">cStr</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Create a new C-string and assign to the JNI string</span>
</span><span class='line'>   <span class="n">message</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewStringUTF</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">&quot;Hello from C&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">message</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// modify the instance variables</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">SetObjectField</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">fidMessage</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><em>访问静态变量</em></p>

<ul>
<li>GetStaticFieldID</li>
<li>GetStatic<type>Field</li>
<li>SetStatic<type>Field</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">JNIEXPORT</span> <span class="kt">void</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNIStaticVariable_modifyStaticVariable</span>
</span><span class='line'>          <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="c1">// Get a reference to this object&#39;s class</span>
</span><span class='line'>   <span class="n">jclass</span> <span class="n">cls</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetObjectClass</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Read the int static variable and modify its value</span>
</span><span class='line'>   <span class="n">jfieldID</span> <span class="n">fidNumber</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetStaticFieldID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span> <span class="s">&quot;number&quot;</span><span class="p">,</span> <span class="s">&quot;D&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">fidNumber</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>   <span class="n">jdouble</span> <span class="n">number</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetStaticDoubleField</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span> <span class="n">fidNumber</span><span class="p">);</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, the double is %f</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'>   <span class="n">number</span> <span class="o">=</span> <span class="mf">77.88</span><span class="p">;</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">SetStaticDoubleField</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span> <span class="n">fidNumber</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><em>访问方法和静态方法</em></p>

<ul>
<li>GetMethodID</li>
<li>Call<type>Method</li>
<li>GetStaticMethodID</li>
<li>CallStatic<type>Method</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">JNIEXPORT</span> <span class="kt">void</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNICallBackMethod_nativeMethod</span>
</span><span class='line'>          <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get a class reference for this object</span>
</span><span class='line'>   <span class="n">jclass</span> <span class="n">thisClass</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetObjectClass</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get the Method ID for method &quot;callback&quot;, which takes no arg and return void</span>
</span><span class='line'>   <span class="n">jmethodID</span> <span class="n">midCallBack</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisClass</span><span class="p">,</span> <span class="s">&quot;callback&quot;</span><span class="p">,</span> <span class="s">&quot;()V&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midCallBack</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, call back Java&#39;s callback()</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="c1">// Call back the method (which returns void), baed on the Method ID</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">CallVoidMethod</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">midCallBack</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="n">jmethodID</span> <span class="n">midCallBackStr</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisClass</span><span class="p">,</span>
</span><span class='line'>                               <span class="s">&quot;callback&quot;</span><span class="p">,</span> <span class="s">&quot;(Ljava/lang/String;)V&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midCallBackStr</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, call back Java&#39;s called(String)</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="n">jstring</span> <span class="n">message</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewStringUTF</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">&quot;Hello from C&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">CallVoidMethod</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">midCallBackStr</span><span class="p">,</span> <span class="n">message</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="n">jmethodID</span> <span class="n">midCallBackAverage</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisClass</span><span class="p">,</span>
</span><span class='line'>                                  <span class="s">&quot;callbackAverage&quot;</span><span class="p">,</span> <span class="s">&quot;(II)D&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midCallBackAverage</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>   <span class="n">jdouble</span> <span class="n">average</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">CallDoubleMethod</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">midCallBackAverage</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, the average is %f</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">average</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="n">jmethodID</span> <span class="n">midCallBackStatic</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetStaticMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisClass</span><span class="p">,</span>
</span><span class='line'>                                 <span class="s">&quot;callbackStatic&quot;</span><span class="p">,</span> <span class="s">&quot;()Ljava/lang/String;&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midCallBackStatic</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>   <span class="n">jstring</span> <span class="n">resultJNIStr</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">CallStaticObjectMethod</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisClass</span><span class="p">,</span> <span class="n">midCallBackStatic</span><span class="p">);</span>
</span><span class='line'>   <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">resultCStr</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetStringUTFChars</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">resultJNIStr</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">resultCStr</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, the returned string is %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">resultCStr</span><span class="p">);</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">ReleaseStringUTFChars</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">resultJNIStr</span><span class="p">,</span> <span class="n">resultCStr</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h5>创建java对象和对象数组</h5>

<p><em>创建java对象</em></p>

<ul>
<li>FindClass</li>
<li>NewObject</li>
<li>AllocObject</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">JNIEXPORT</span> <span class="n">jobject</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNIConstructor_getIntegerObject</span>
</span><span class='line'>          <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">jint</span> <span class="n">number</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="c1">// Get a class reference for java.lang.Integer</span>
</span><span class='line'>   <span class="n">jclass</span> <span class="n">cls</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">FindClass</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">&quot;java/lang/Integer&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get the Method ID of the constructor which takes an int</span>
</span><span class='line'>   <span class="n">jmethodID</span> <span class="n">midInit</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span> <span class="s">&quot;&lt;init&gt;&quot;</span><span class="p">,</span> <span class="s">&quot;(I)V&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midInit</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>   <span class="c1">// Call back constructor to allocate a new instance, with an int argument</span>
</span><span class='line'>   <span class="n">jobject</span> <span class="n">newObj</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewObject</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span> <span class="n">midInit</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Try runnning the toString() on this newly create object</span>
</span><span class='line'>   <span class="n">jmethodID</span> <span class="n">midToString</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span> <span class="s">&quot;toString&quot;</span><span class="p">,</span> <span class="s">&quot;()Ljava/lang/String;&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midToString</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>   <span class="n">jstring</span> <span class="n">resultStr</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">CallObjectMethod</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">newObj</span><span class="p">,</span> <span class="n">midToString</span><span class="p">);</span>
</span><span class='line'>   <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">resultCStr</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetStringUTFChars</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">resultStr</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C: the number is %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">resultCStr</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="k">return</span> <span class="n">newObj</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><em>创建java数组</em></p>

<ul>
<li>NewObjectArray</li>
<li>GetObjectArrayElement</li>
<li>setObjectArrayElement</li>
</ul>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">JNIEXPORT</span> <span class="n">jobjectArray</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNIObjectArray_sumAndAverage</span>
</span><span class='line'>          <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">jobjectArray</span> <span class="n">inJNIArray</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="c1">// Get a class reference for java.lang.Integer</span>
</span><span class='line'>   <span class="n">jclass</span> <span class="n">classInteger</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">FindClass</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">&quot;java/lang/Integer&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="c1">// Use Integer.intValue() to retrieve the int</span>
</span><span class='line'>   <span class="n">jmethodID</span> <span class="n">midIntValue</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">classInteger</span><span class="p">,</span> <span class="s">&quot;intValue&quot;</span><span class="p">,</span> <span class="s">&quot;()I&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midIntValue</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get the value of each Integer object in the array</span>
</span><span class='line'>   <span class="n">jsize</span> <span class="n">length</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetArrayLength</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">inJNIArray</span><span class="p">);</span>
</span><span class='line'>   <span class="n">jint</span> <span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span><span class='line'>   <span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
</span><span class='line'>   <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">length</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">jobject</span> <span class="n">objInteger</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetObjectArrayElement</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">inJNIArray</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
</span><span class='line'>      <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">objInteger</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>      <span class="n">jint</span> <span class="n">value</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">CallIntMethod</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">objInteger</span><span class="p">,</span> <span class="n">midIntValue</span><span class="p">);</span>
</span><span class='line'>      <span class="n">sum</span> <span class="o">+=</span> <span class="n">value</span><span class="p">;</span>
</span><span class='line'>   <span class="p">}</span>
</span><span class='line'>   <span class="kt">double</span> <span class="n">average</span> <span class="o">=</span> <span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">sum</span> <span class="o">/</span> <span class="n">length</span><span class="p">;</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, the sum is %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">sum</span><span class="p">);</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, the average is %f</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">average</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get a class reference for java.lang.Double</span>
</span><span class='line'>   <span class="n">jclass</span> <span class="n">classDouble</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">FindClass</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">&quot;java/lang/Double&quot;</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Allocate a jobjectArray of 2 java.lang.Double</span>
</span><span class='line'>   <span class="n">jobjectArray</span> <span class="n">outJNIArray</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewObjectArray</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">classDouble</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Construct 2 Double objects by calling the constructor</span>
</span><span class='line'>   <span class="n">jmethodID</span> <span class="n">midDoubleInit</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">classDouble</span><span class="p">,</span> <span class="s">&quot;&lt;init&gt;&quot;</span><span class="p">,</span> <span class="s">&quot;(D)V&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midDoubleInit</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>   <span class="n">jobject</span> <span class="n">objSum</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewObject</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">classDouble</span><span class="p">,</span> <span class="n">midDoubleInit</span><span class="p">,</span> <span class="p">(</span><span class="kt">double</span><span class="p">)</span><span class="n">sum</span><span class="p">);</span>
</span><span class='line'>   <span class="n">jobject</span> <span class="n">objAve</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewObject</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">classDouble</span><span class="p">,</span> <span class="n">midDoubleInit</span><span class="p">,</span> <span class="n">average</span><span class="p">);</span>
</span><span class='line'>   <span class="c1">// Set to the jobjectArray</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">SetObjectArrayElement</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">outJNIArray</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">objSum</span><span class="p">);</span>
</span><span class='line'>   <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">SetObjectArrayElement</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">outJNIArray</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">objAve</span><span class="p">);</span>
</span><span class='line'>
</span><span class='line'>   <span class="k">return</span> <span class="n">outJNIArray</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h5>本地和全局变量</h5>

<p>任何类似FindClass(), GetMethodID(), GetFieldID()返回的引用是一个本地引用。</p>

<p>想要使用全局引用的话，需要使用<code>NewGlobalRef()</code>，<code>DeleteGlobalRef()</code></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="c1">// Global Reference to the Java class &quot;java.lang.Integer&quot;</span>
</span><span class='line'><span class="k">static</span> <span class="n">jclass</span> <span class="n">classInteger</span><span class="p">;</span>
</span><span class='line'><span class="k">static</span> <span class="n">jmethodID</span> <span class="n">midIntegerInit</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'><span class="n">jobject</span> <span class="nf">getInteger</span><span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">jint</span> <span class="n">number</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get a class reference for java.lang.Integer if missing</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">classInteger</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">printf</span><span class="p">(</span><span class="s">&quot;Find java.lang.Integer</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
</span><span class='line'>    <span class="n">jclass</span> <span class="n">classIntegerLocal</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">FindClass</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">&quot;java/lang/Integer&quot;</span><span class="p">);</span>
</span><span class='line'>      <span class="c1">// Create a global reference from the local reference</span>
</span><span class='line'>      <span class="n">classInteger</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewGlobalRef</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">classIntegerLocal</span><span class="p">);</span>
</span><span class='line'>      <span class="c1">// No longer need the local reference, free it!</span>
</span><span class='line'>      <span class="c1">//(*env)-&gt;DeleteLocalRef(env, classIntegerLocal);</span>
</span><span class='line'>   <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">classInteger</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Get the Method ID of the Integer&#39;s constructor if missing</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midIntegerInit</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="n">printf</span><span class="p">(</span><span class="s">&quot;Get Method ID for java.lang.Integer&#39;s constructor</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">);</span>
</span><span class='line'>      <span class="n">midIntegerInit</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">GetMethodID</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">classInteger</span><span class="p">,</span> <span class="s">&quot;&lt;init&gt;&quot;</span><span class="p">,</span> <span class="s">&quot;(I)V&quot;</span><span class="p">);</span>
</span><span class='line'>   <span class="p">}</span>
</span><span class='line'>   <span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">midIntegerInit</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
</span><span class='line'>
</span><span class='line'>   <span class="c1">// Call back constructor to allocate a new instance, with an int argument</span>
</span><span class='line'>   <span class="n">jobject</span> <span class="n">newObj</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewObject</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">classInteger</span><span class="p">,</span> <span class="n">midIntegerInit</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'>   <span class="n">printf</span><span class="p">(</span><span class="s">&quot;In C, constructed java.lang.Integer with number %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'>   <span class="k">return</span> <span class="n">newObj</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">JNIEXPORT</span> <span class="n">jobject</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNIReference_getIntegerObject</span>
</span><span class='line'>          <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">jint</span> <span class="n">number</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="k">return</span> <span class="n">getInteger</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">JNIEXPORT</span> <span class="n">jobject</span> <span class="n">JNICALL</span> <span class="nf">Java_TestJNIReference_anotherGetIntegerObject</span>
</span><span class='line'>          <span class="p">(</span><span class="n">JNIEnv</span> <span class="o">*</span><span class="n">env</span><span class="p">,</span> <span class="n">jobject</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">jint</span> <span class="n">number</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>   <span class="k">return</span> <span class="n">getInteger</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">thisObj</span><span class="p">,</span> <span class="n">number</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fresco 简介]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/09/12/introducing-fresco/"/>
    <updated>2015-09-12T17:42:18+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/09/12/introducing-fresco</id>
    <content type="html"><![CDATA[<p>翻译自<a href="https://code.facebook.com/posts/366199913563917/introducing-fresco-a-new-image-library-for-android/">Introducing Fresco: A new image library for Android</a></p>

<p>这里并不是单纯的翻译，只是试图总结一下fresco的特点</p>

<!--more-->


<p>fresco是facebook开源的管理图片的库，主要还是为了管理里图片使用的内存</p>

<h4>不同的内存区域</h4>

<p>对于Android来说，可以使用的内存区域包括:</p>

<ul>
<li><code>java heap</code></li>
<li><code>native heap</code></li>
<li><code>ashmem</code></li>
</ul>


<p><code>ashmem</code>非常像<code>native heap</code>，但是有趣的是，它可以<code>pin/unpin</code>。所谓的<code>unpin</code>其实就是lazy free。也就是说，仅仅当Android需要更多内存的时候，才会释放这块内存。当Android重新<code>pin</code>这块内存时，如果这块内存不曾被是放过的话，那么原来的数据还在那里。</p>

<h4>Purgeable bitmaps</h4>

<p><code>ashmem</code>并不能被java应用直接访问，除了一些特殊情况，恰好，图片就是其中的一个。当你创建一个解码过的图片，<code>bitmap</code>，api允许你指定这个图片是<code>purgeable</code>.</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">BitmapFactory</span><span class="o">.</span><span class="na">Options</span> <span class="o">=</span> <span class="k">new</span> <span class="n">BitmapFactory</span><span class="o">.</span><span class="na">Options</span><span class="o">();</span>
</span><span class='line'><span class="n">options</span><span class="o">.</span><span class="na">inPurgeable</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'><span class="n">Bitmap</span> <span class="n">bitmap</span> <span class="o">=</span> <span class="n">BitmapFactory</span><span class="o">.</span><span class="na">decodeByteArray</span><span class="o">(</span><span class="n">jpeg</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">jpeg</span><span class="o">.</span><span class="na">length</span><span class="o">,</span> <span class="n">options</span><span class="o">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>Purgeable的bitmap就在ashmem里。然而，garbage collector并不自动回收这些内存。Android系统只是在渲染系统渲染的时候<code>pin</code>住这些内存，然后在渲染结束后<code>unpin</code>他们。如果这些<code>unpined</code>图片需要再次被渲染的话，Android就会重新取得需要的内容，如果有必要的话，会重新在线(on the fly)解码。</p>

<p>但是在线解码(on the fly decode)发生在主线程里，由于这个原因，Google并不建议使用这个特性。目前的建议是使用<code>inBitmap</code>。但是这个新标志只有在android3.0里才存在。此外在4.4之前，这个特性还有个限制，是要求新解压的图片和原来的图片的大小要一致。这个要求显然并不适合大多数场景。</p>

<h4>鱼和熊掌可以兼得</h4>

<p>我们发现了一个既可以不用频繁释放／分配内存，又可以不阻塞UI的办法。也就是说，如果我们事先在非UI线程pin好一块内存，然后只要永远不要unpin它，这样我们就在ashmem上得到了一块内存，但是却不会引起UI阻塞的问题。非常幸运，我们NDK中有一个函数就是干这个的，<code>AdnroidBitmap_lockPixels</code>。这个函数设计之初是用来和<code>unlockPixels</code>配合使用来unpin这块内存的。当我们故意调用lockPixels但是并不调用unlockPixels时候，我们就很安全的在Java Heap之外得到了一块并不阻塞UI线程的内存。</p>

<h4>像C++一样思考</h4>

<p>ashmem没有类似garbage collector来保证不会内存泄漏。所以我们需要自己来保证。</p>

<p>在C++里，通常的解决办法是使用smart pointer类来实现引用计数。但这使用了cpp语言的工具，copy constructor，assignment constructor，deterministic destructor。这些语法糖在java中并不存在。所以我们自己要实现类似的机制。</p>

<p>我们通过两个类来实现这个机制。一个叫做<code>SharedReference</code>。这个类有两个方法，一个是<code>addReference</code>，一个是<code>deleteReferece</code>。通过这个来实现引用计数。</p>

<p>当然这个对于java程序员来说，明显很容易出错。java语言设计的时候就是要避免这样做。所以在<code>SharedReference</code>顶上，我们设计了<code>CloseableReference</code>。它是现实了<code>Closeable</code>接口，并且也实现了<code>cloneabel</code>。在构造函数和<code>clone()</code>里我们调用<code>addReferece()</code>。在<code>close()</code>里，我们调用<code>deleteReference()</code>。所以java开发者只需要遵循两个原则：</p>

<ul>
<li>给一个CloseableReference赋值时候，调<code>.clone()</code>。</li>
<li>离开作用域时，调用<code>.close()</code>，通常是在一个final块里。</li>
</ul>


<h4>它不仅仅是一个loader，更是一个pipeline</h4>

<p><img class="center" src="http://IamAlchemist.github.io/images/fresco/fresco_imagepipeline.png" width="600"></p>

<p>在移动设备上显示一张图片要涉及很多步骤，如果我们把这些步骤看作是<code>pipeline</code>而不是<code>loader</code>，那么事情会完全不一样。每一步都应该尽可能的独立于其他步骤，每一步获得一些参数的输入，而产出一些结果。一些可能需要可以并行，一些需要串行。有一些仅仅需要在一些特定条件下执行，有一些对执行他们的线程有特定要求。而且考虑到弱网络和大图片，我们希望用户可以尽可能快的看到图片，即使是图片并没有完全下载下来。</p>

<p>对于Java来说，一般异步代码同步的时候我们会用到<code>Future</code>。但Future只能在执行完毕的时候带回来一个结果。当我们处理大图片的时候，我们需要处理一系列的结果。</p>

<p>我们的解决办法是涉及一个泛化版的Future，<code>DataSource</code>。它提供一个订阅的方法，调用者必须传递一个<code>DataSubscriber</code>和<code>Executor</code>给它。DataSubscriber将会收到DataSource发来的中间结果或者是最终结果的通知，并且会提供一个简单的办法去区分这两者。</p>

<p>在底层，上图里的每一个盒子都是使用一个新的架构实现的，叫做Producer/Consumer。这个架构是学习<code>ReactiveX</code>架构而搭建的。整个接口非常简洁，<code>Producer</code>只有一个方法，<code>produceResults</code>，它只有一个参数是<code>Consumer</code>对象。相对应的，<code>Consumer</code>只有一个方法叫做<code>onNewResult</code>。</p>

<p>我们使用一个向下面这样的一个系统来使producters变成一个链条。假设我们有一个producer，它的工作就是把类型I变成类型O。看起来如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">OutputProducer</span><span class="o">&lt;</span><span class="n">I</span><span class="o">,</span> <span class="n">O</span><span class="o">&gt;</span> <span class="kd">implements</span> <span class="n">Producer</span><span class="o">&lt;</span><span class="n">O</span><span class="o">&gt;</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">private</span> <span class="kd">final</span> <span class="n">Producer</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span> <span class="n">mInputProducer</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">public</span> <span class="nf">OutputProducer</span><span class="o">(</span><span class="n">Producer</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span> <span class="n">inputProducer</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">this</span><span class="o">.</span><span class="na">mInputProducer</span> <span class="o">=</span> <span class="n">inputProducer</span><span class="o">;</span>
</span><span class='line'>  <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">public</span> <span class="kt">void</span> <span class="nf">produceResults</span><span class="o">(</span><span class="n">Consumer</span><span class="o">&lt;</span><span class="n">O</span><span class="o">&gt;</span> <span class="n">outputConsumer</span><span class="o">,</span> <span class="n">ProducerContext</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="n">Consumer</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span> <span class="n">inputConsumer</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">InputConsumer</span><span class="o">(</span><span class="n">outputConsumer</span><span class="o">);</span>
</span><span class='line'>    <span class="n">mInputProducer</span><span class="o">.</span><span class="na">produceResults</span><span class="o">(</span><span class="n">inputConsumer</span><span class="o">,</span> <span class="n">context</span><span class="o">);</span>
</span><span class='line'>  <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>  <span class="kd">private</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">InputConsumer</span> <span class="kd">implements</span> <span class="n">Consumer</span><span class="o">&lt;</span><span class="n">I</span><span class="o">&gt;</span> <span class="o">{</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">Consumer</span><span class="o">&lt;</span><span class="n">O</span><span class="o">&gt;</span> <span class="n">mOutputConsumer</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">InputConsumer</span><span class="o">(</span><span class="n">Consumer</span><span class="o">&lt;</span><span class="n">O</span><span class="o">&gt;</span> <span class="n">outputConsumer</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>      <span class="n">mOutputConsumer</span> <span class="o">=</span> <span class="n">outputConsumer</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onNewResult</span><span class="o">(</span><span class="n">I</span> <span class="n">newResult</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">isLast</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>      <span class="n">O</span> <span class="n">output</span> <span class="o">=</span> <span class="n">doActualWork</span><span class="o">(</span><span class="n">newResult</span><span class="o">);</span>
</span><span class='line'>      <span class="n">mOutputConsumer</span><span class="o">.</span><span class="na">onNewResult</span><span class="o">(</span><span class="n">output</span><span class="o">,</span> <span class="n">isLast</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>  <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>这个设计使得我们可以组建一个非常复杂的工作步骤链条，但是却能保证每一步逻辑上的独立性。</p>

<h4>动画－－从一到多</h4>

<p>表情一般来说是GIF或者WebP格式的，这带来了挑战，一个动画由许多bitmap组成，每一个都需要解码，存储和显示。对于大的动画来说，在内存中存储每一帧显然是不可能的。</p>

<p>所以我们设计了<code>AnimatedDrawable</code>，实现了Android的<code>Animatable</code>接口，可以支持以上两种格式，并且我们做了优化，如果比较小，我们可以把所有帧放在内存中，否则我们在线解码。不过这些都是高度可定制的</p>

<h4>关于Drawee</h4>

<p>我们以前的实现使用了View，当图片下载好之后把一个placeholder的View和交换，但是这样效率不高，因为换View会引起Android重新计算整个layout pass。所以一个更合理的做法是使用Android的Drawable，它可以实时交换而不引起任何其他代价。</p>

<p>所以我们引入了<code>Drawee</code>。这个MVC类似的架构用来显示图片。Modal叫做<code>DraweeHierarchy</code>，它由有层次的Drawable组成，每一个实现特定的功能，imaging，layering，fade-in，scaling等。</p>

<p><code>DraweeControllers</code>连接image pipeline和处理image后台的操作。它从pipeline收到通知，然后决定怎么处理结果。它决定了DrawHierarchy实际显示了什么，不论是placeholder，错误，或者准备好的图片。</p>

<p><code>DraweeViews</code>仅仅有非常有限的功能，但是它提供的功能却是决定性的。它接受Android系统的事件来发出信号说，这个view是不是还在屏幕上显示。当不在屏幕上的时候，DraweeView可以让DraweeController释放被图片使用资源。同时如果这个图片还没有下载的话，它可以取消，这样就可以节约网络带宽的使用。</p>

<p><code>完</code></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[新Android Gradle Build Tools: Gradle 2.5]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/09/07/new-android-gradle-build-tools-the-new-dsl-structure-and-gradle-2-dot-5/"/>
    <updated>2015-09-07T16:22:45+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/09/07/new-android-gradle-build-tools-the-new-dsl-structure-and-gradle-2-dot-5</id>
    <content type="html"><![CDATA[<p>Android Studio 1.3已经除了稳定版了。新特性包括了完全NDK支持，而且一个主要的更改是DSL(Domain-Specific Language)的变化。</p>

<p>翻译自<a href="http://inthecheesefactory.com/blog/new-gradle-build-tools-with-gradle-2.5/en">inthechessefactory</a></p>

<!--more-->


<h4>什么是Android Gradle Build Tools</h4>

<p>在把每个module的build.gradle文件传递给Gradle之前，Android Gradle Build Tools 用来提前处理下这些文件。</p>

<p>Gradle Build Tools的版本是在project的build.gradle里指定的，类似：</p>

<pre><code>dependencies {
    classpath 'com.android.tools.build:gradle:1.2.3'
}
</code></pre>

<p>Gradle Build Tools版本和Gradle版本对应关系如下：</p>

<table>
<thead>
<tr>
<th style="text-align:left;">Android Gradle Plugin </th>
<th style="text-align:left;"> Gradle</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">1.0.0-1.1.3           </td>
<td style="text-align:left;">2.2.1-2.3</td>
</tr>
<tr>
<td style="text-align:left;">1.2+                  </td>
<td style="text-align:left;">2..2.1+</td>
</tr>
</tbody>
</table>


<h4>The new Android Gradle Build Tools</h4>

<p>使用新的Gradle Build Tools的话，只需要换掉build tools的version</p>

<pre><code>dependencies {
    classpath 'com.android.tools.build:gradle-experimental:0.1.0'
}
</code></pre>

<p>不过只有gradle2.5才能匹配使用，所以需要设置gradle-wrapper.properties</p>

<pre><code>distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-bin.zip
</code></pre>

<p>然后像下面这样编辑模块的build.gradle</p>

<pre><code>apply plugin: 'com.android.model.application'

model {
    android {
        compileSdkVersion = 22
        buildToolsVersion = "23.0.0 rc3"

        defaultConfig.with {
            applicationId = "com.inthecheesefactory.hellojni25"
            minSdkVersion.apiLevel = 15
            targetSdkVersion.apiLevel = 22
            versionCode = 1
            versionName = "1.0"
        }
    }

    android.buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles += file('proguard-rules.pro')
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
}
</code></pre>

<p>仔细看就会发现，plugin不再是<code>com.android.application</code>，而是<code>com.android.model.application</code>。<br/>
<code>+=</code>被引入表示在一个collection中增加一些元素。</p>

<h4>支持 NDK</h4>

<p>修改项目的local.properites文件</p>

<pre><code>ndk.dir=PATH_TO_NDK_ROOT
</code></pre>

<p>，或者直接使用android studio下载ndk</p>

<p>然后在java的package里创建<code>HelloJni.java</code>文件</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloJni</span> <span class="o">{</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kd">native</span> <span class="n">String</span> <span class="nf">stringFromJNI</span><span class="o">();</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>在src/main目录下创建jni文件夹，然后创建hello-jni.c文件</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="cp">#include &lt;string.h&gt;</span>
</span><span class='line'><span class="cp">#include &lt;jni.h&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="n">jstring</span>
</span><span class='line'><span class="nf">Java_com_inthecheesefactory_hellojni25_HelloJni_stringFromJNI</span><span class="p">(</span> <span class="n">JNIEnv</span><span class="o">*</span> <span class="n">env</span><span class="p">,</span>
</span><span class='line'>                                                  <span class="n">jobject</span> <span class="n">thiz</span> <span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'><span class="cp">#if defined(__arm__)</span>
</span><span class='line'>  <span class="cp">#if defined(__ARM_ARCH_7A__)</span>
</span><span class='line'>    <span class="cp">#if defined(__ARM_NEON__)</span>
</span><span class='line'>      <span class="cp">#if defined(__ARM_PCS_VFP)</span>
</span><span class='line'>        <span class="cp">#define ABI &quot;armeabi-v7a/NEON (hard-float)&quot;</span>
</span><span class='line'>      <span class="cp">#else</span>
</span><span class='line'>        <span class="cp">#define ABI &quot;armeabi-v7a/NEON&quot;</span>
</span><span class='line'>      <span class="cp">#endif</span>
</span><span class='line'>    <span class="cp">#else</span>
</span><span class='line'>      <span class="cp">#if defined(__ARM_PCS_VFP)</span>
</span><span class='line'>        <span class="cp">#define ABI &quot;armeabi-v7a (hard-float)&quot;</span>
</span><span class='line'>      <span class="cp">#else</span>
</span><span class='line'>        <span class="cp">#define ABI &quot;armeabi-v7a&quot;</span>
</span><span class='line'>      <span class="cp">#endif</span>
</span><span class='line'>    <span class="cp">#endif</span>
</span><span class='line'>  <span class="cp">#else</span>
</span><span class='line'>   <span class="cp">#define ABI &quot;armeabi&quot;</span>
</span><span class='line'>  <span class="cp">#endif</span>
</span><span class='line'><span class="cp">#elif defined(__i386__)</span>
</span><span class='line'>   <span class="cp">#define ABI &quot;x86&quot;</span>
</span><span class='line'><span class="cp">#elif defined(__x86_64__)</span>
</span><span class='line'>   <span class="cp">#define ABI &quot;x86_64&quot;</span>
</span><span class='line'><span class="cp">#elif defined(__mips64)  </span><span class="cm">/* mips64el-* toolchain defines __mips__ too */</span><span class="cp"></span>
</span><span class='line'>   <span class="cp">#define ABI &quot;mips64&quot;</span>
</span><span class='line'><span class="cp">#elif defined(__mips__)</span>
</span><span class='line'>   <span class="cp">#define ABI &quot;mips&quot;</span>
</span><span class='line'><span class="cp">#elif defined(__aarch64__)</span>
</span><span class='line'>   <span class="cp">#define ABI &quot;arm64-v8a&quot;</span>
</span><span class='line'><span class="cp">#else</span>
</span><span class='line'>   <span class="cp">#define ABI &quot;unknown&quot;</span>
</span><span class='line'><span class="cp">#endif</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">return</span> <span class="p">(</span><span class="o">*</span><span class="n">env</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">NewStringUTF</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="s">&quot;Hello from JNI !!  Compiled with ABI &quot;</span> <span class="n">ABI</span> <span class="s">&quot;.&quot;</span><span class="p">);</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>请记住让<code>com_inthecheesefactory_hellojni25</code>和HelloJni.java的包名是一致的。makefile不再需要了。</p>

<p>现在在<code>MainActivity.java</code>里测试一下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MainActivity</span> <span class="kd">extends</span> <span class="n">AppCompatActivity</span> <span class="o">{</span>
</span><span class='line'>  <span class="nd">@Override</span>
</span><span class='line'>  <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>      <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
</span><span class='line'>      <span class="n">setContentView</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">activity_main</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">Toast</span><span class="o">.</span><span class="na">makeText</span><span class="o">(</span><span class="n">MainActivity</span><span class="o">.</span><span class="na">this</span><span class="o">,</span>
</span><span class='line'>                    <span class="k">new</span> <span class="nf">HelloJni</span><span class="o">().</span><span class="na">stringFromJNI</span><span class="o">(),</span>
</span><span class='line'>                    <span class="n">Toast</span><span class="o">.</span><span class="na">LENGTH_LONG</span><span class="o">).</span><span class="na">show</span><span class="o">();</span>
</span><span class='line'>  <span class="o">}</span>
</span><span class='line'>    <span class="o">...</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">static</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">System</span><span class="o">.</span><span class="na">loadLibrary</span><span class="o">(</span><span class="s">&quot;hello-jni&quot;</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p><a href="https://www.youtube.com/watch?v=SeKXi-viRrk">more video</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Create Universal Framework]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/07/22/create-universal-framework/"/>
    <updated>2015-07-22T19:45:58+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/07/22/create-universal-framework</id>
    <content type="html"><![CDATA[<p>xcode很有意思，当选择平台是iOS device时，framework支持的architecture是arm系列的，然而如果是iOS simulator的话，又仅产生支持x86_64系列的architecture。</p>

<p>那么当我们如何编译framework时使它可以支持所有architecture呢</p>

<p><a href="https://medium.com/@syshen/create-an-ios-universal-framework-148eb130a46c">参考资料1</a></p>

<p><a href="https://kodmunki.wordpress.com/2015/03/04/cocoa-touch-frameworks-for-ios8-remix/">参考资料2</a></p>

<!--more-->


<p>要点如下：</p>

<p>在build phases里增加一个脚本</p>

<pre><code>######################
# Options
######################

REVEAL_ARCHIVE_IN_FINDER=false

FRAMEWORK_NAME="${PROJECT_NAME}"

SIMULATOR_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework"

DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework"

UNIVERSAL_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal"

FRAMEWORK="${UNIVERSAL_LIBRARY_DIR}/${FRAMEWORK_NAME}.framework"


######################
# Build Frameworks
######################

xcodebuild -workspace ${PROJECT_NAME}.xcworkspace -scheme ${PROJECT_NAME} -sdk iphonesimulator -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator 2&gt;&amp;1

xcodebuild -workspace ${PROJECT_NAME}.xcworkspace -scheme ${PROJECT_NAME} -sdk iphoneos -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos 2&gt;&amp;1

######################
# Create directory for universal
######################

rm -rf "${UNIVERSAL_LIBRARY_DIR}"

mkdir "${UNIVERSAL_LIBRARY_DIR}"

mkdir "${FRAMEWORK}"


######################
# Copy files Framework
######################

cp -r "${DEVICE_LIBRARY_PATH}/." "${FRAMEWORK}"


######################
# Make an universal binary
######################

lipo "${SIMULATOR_LIBRARY_PATH}/${FRAMEWORK_NAME}" "${DEVICE_LIBRARY_PATH}/${FRAMEWORK_NAME}" -create -output "${FRAMEWORK}/${FRAMEWORK_NAME}" | echo

# For Swift framework, Swiftmodule needs to be copied in the universal framework
if [ -d "${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then
    cp -f ${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo
fi

if [ -d "${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then
    cp -f ${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo
fi

######################
# On Release, copy the result to release directory
######################

OUTPUT_DIR="${PROJECT_DIR}/Output/${FRAMEWORK_NAME}-${CONFIGURATION}-iphoneuniversal/"

rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

cp -r "${FRAMEWORK}" "$OUTPUT_DIR"

if [ ${REVEAL_ARCHIVE_IN_FINDER} = true ]; then
    open "${OUTPUT_DIR}/"
fi
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Override Function in Extension]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/07/22/override-function-in-extension/"/>
    <updated>2015-07-22T00:00:00+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/07/22/override-function-in-extension</id>
    <content type="html"><![CDATA[<hr />

<p>layout: post
title: &ldquo;到底能不能在extension里override一个函数？&rdquo;
date: 2015-07-22 11:12:03 +0800
comments: true</p>

<h2>categories: iOS Swift</h2>

<p>Swift教程中明确说了，extension并不能override一个已有的函数！可是最近发现有人extension UIImageView时，可以<code>override layoutSubviews()</code>，到底什么鬼？？</p>

<!--more-->


<p>在<a href="http://stackoverflow.com/questions/27109006/can-you-override-between-extensions-in-swift-or-not-compiler-seems-confused">stackoverflow</a>上找到了答案，并且自己也确认过了。</p>

<p>解释是这样的：</p>

<p>至少在目前版本（swift1.1， 1.2），只要在如下两种情况下就可以override函数</p>

<ul>
<li>涉及到的类都是从NSObject继承来的,不使用inout修饰符并且没有enum</li>
<li>或者使用了@objc修饰符的函数</li>
</ul>


<p>核心思想是，只有<em>Objective-C compatible</em>的方法和属性才能在extension里override</p>

<p>请参考下面的例子</p>

<h4>例子1</h4>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
</pre></td><td class='code'><pre><code class='swift'><span class='line'><span class="k">class</span> <span class="nl">A</span> <span class="p">:</span> <span class="bp">NSObject</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'><span class="k">class</span> <span class="nl">B</span> <span class="p">:</span> <span class="n">A</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nl">SubNSObject</span> <span class="p">:</span> <span class="bp">NSObject</span> <span class="p">{}</span>
</span><span class='line'><span class="k">class</span> <span class="n">NotSubbed</span> <span class="p">{}</span>
</span><span class='line'><span class="k">enum</span> <span class="n">SomeEnum</span> <span class="p">{</span> <span class="k">case</span> <span class="n">c1</span><span class="p">,</span> <span class="n">c2</span><span class="p">;</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">extension</span> <span class="n">A</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="k">var</span> <span class="nl">y</span> <span class="p">:</span> <span class="n">String</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">{</span> <span class="k">return</span> <span class="s">&quot;YinA&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span>
</span><span class='line'>    <span class="k">func</span> <span class="n">f</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">A</span> <span class="p">{</span> <span class="k">return</span> <span class="n">A</span><span class="p">();</span> <span class="p">}</span>
</span><span class='line'>    <span class="k">func</span> <span class="n">g</span><span class="p">(</span><span class="nl">val</span><span class="p">:</span> <span class="n">SubNSObject</span><span class="p">,</span> <span class="nl">test</span><span class="p">:</span> <span class="n">Bool</span> <span class="o">=</span> <span class="nb">false</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">func</span> <span class="n">h</span><span class="p">(</span><span class="nl">val</span><span class="p">:</span> <span class="n">NotSubbed</span><span class="p">,</span> <span class="nl">test</span><span class="p">:</span> <span class="n">Bool</span> <span class="o">=</span> <span class="nb">false</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'>    <span class="k">func</span> <span class="n">j</span><span class="p">(</span><span class="nl">val</span><span class="p">:</span> <span class="n">SomeEnum</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'>    <span class="k">func</span> <span class="n">k</span><span class="p">(</span><span class="nl">val</span><span class="p">:</span> <span class="n">SubNSObject</span><span class="p">,</span> <span class="k">inout</span> <span class="nl">test</span><span class="p">:</span> <span class="n">Bool</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">extension</span> <span class="n">B</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="c1">// THESE OVERIDES DO COMPILE:</span>
</span><span class='line'>    <span class="kr">override</span> <span class="k">var</span>  <span class="nl">y</span> <span class="p">:</span> <span class="n">String</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">{</span> <span class="k">return</span> <span class="s">&quot;YinB&quot;</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span>
</span><span class='line'>    <span class="kr">override</span> <span class="k">func</span> <span class="n">f</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">A</span> <span class="p">{</span> <span class="k">return</span> <span class="n">A</span><span class="p">();</span> <span class="p">}</span>
</span><span class='line'>    <span class="kr">override</span> <span class="k">func</span> <span class="n">g</span><span class="p">(</span><span class="nl">val</span><span class="p">:</span> <span class="n">SubNSObject</span><span class="p">,</span> <span class="nl">test</span><span class="p">:</span> <span class="n">Bool</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="c1">// THESE OVERIDES DO NOT COMPILE:</span>
</span><span class='line'>    <span class="c1">//override func h(val: NotSubbed, test: Bool = false) { }</span>
</span><span class='line'>    <span class="c1">//override func j(val: SomeEnum) { }</span>
</span><span class='line'>    <span class="c1">//override func k(val: SubNSObject, inout test: Bool) { }</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<h4>例子2</h4>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='swift'><span class='line'><span class="k">class</span> <span class="n">A</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nl">B</span> <span class="p">:</span> <span class="n">A</span> <span class="p">{</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">extension</span> <span class="n">A</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>    <span class="p">@</span><span class="n">objc</span> <span class="k">var</span> <span class="nl">y</span> <span class="p">:</span> <span class="n">String</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">{</span> <span class="k">return</span> <span class="s">&quot;YinA&quot;</span> <span class="p">}</span> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">extension</span> <span class="n">B</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>   <span class="p">@</span><span class="n">objc</span> <span class="kr">override</span> <span class="k">var</span> <span class="nl">y</span> <span class="p">:</span> <span class="n">String</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">{</span> <span class="k">return</span> <span class="s">&quot;YinB&quot;</span> <span class="p">}</span> <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用代码来控制AutoLayout]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/07/16/working-with-auto-layout-programmatically/"/>
    <updated>2015-07-16T14:15:18+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/07/16/working-with-auto-layout-programmatically</id>
    <content type="html"><![CDATA[<p><a href="https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutinCode/AutoLayoutinCode.html">Apple参考文档</a></p>

<h3>创建Constraint</h3>

<p>你可以使用<code>NSLayoutConstraint</code>来表示constrains。</p>

<p>如果要创建constraints，一般要使用 <code>constraintsWithVisualFormat:options:metrics:views:</code>。</p>

<p>第一个参数是一个<code>visual format string</code>，这种<code>visual format language</code>已经尽可能的是自我解释的。一个view使用一个方括号来代表，view之间的连接用横杠来代表。<code>visual format language</code>的语法参见<a href="https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage/VisualFormatLanguage.html#//apple_ref/doc/uid/TP40010853-CH3-SW1">Visual Format Language</a></p>

<p>比如说，</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-07-16_1.png" width="273"></p>

<p>上图可以表示为:</p>

<pre><code>[button1]-12-[button2]
</code></pre>

<p>如果是标准的Aqua距离的话，可以不用标注数字</p>

<pre><code>[button1]-[button2]
</code></pre>

<!--more-->


<p>view的名字来自于参数<code>views</code>字典。key就是这里用到名字，而value是对应的view对象。</p>

<p>可以使用<code>NSDictionaryOfVariableBindings</code>来创建该字典，该函数使用view对象的名字来作为key值</p>

<pre><code>NSDictionary *viewsDictionary =
    NSDictionaryOfVariableBindings(self.button1, self.button2);

NSArray *constraints =
    [NSLayoutConstraint constraintsWithVisualFormat:@"[button1]-[button2]"
                        options:0 metrics:nil views:viewsDictionary];
</code></pre>

<p>并不是每一种constraint都可以通过visual format language来表示的。比如有一种常用的constraint不能用该语言来表达，比如固定宽高比，这时候需要用这样的函数：</p>

<p><code>constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constraint:</code></p>

<p>比如上面contraint还可以这样创建</p>

<pre><code>[NSLayoutConstraint constraintWithItem:self.button1 
                             attribute:NSLayoutAttributeRight
                             relatedBy:NSLayoutRelationEqual 
                                toItem:self.button2
                             attribute:NSLayoutAttributeLeft 
                            multiplier:1.0 
                              constant:-12.0];
</code></pre>

<h3>Installing Constraints</h3>

<p>我们必须把constraint加到view中，这个view应该是所有涉及到的view的祖先view，通常是最近的那个祖先view。</p>

<p>关于这个我们可以使用<code>NSView</code>的<code>addConstraint:</code></p>

<p>相关的函数还有：</p>

<ul>
<li><code>removeConstraint:</code></li>
<li><code>constraints</code></li>
<li><code>fittingSize</code></li>
</ul>


<h3>参考资料</h3>

<ul>
<li>最重要的一个开源库可以帮助我们不用写那么多无聊的代码</li>
</ul>


<p><a href="https://github.com/SnapKit/Masonry">Masonry</a></p>

<pre><code>[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview).with.insets(padding);
}];
</code></pre>

<ul>
<li><a href="http://segmentfault.com/a/1190000000646452">从此爱上iOS Autolayout</a></li>
<li><a href="http://www.raywenderlich.com/50317/beginning-auto-layout-tutorial-in-ios-7-part-1">Beginning Auto Layout Tutorial in iOS 7: Part 1</a></li>
<li><a href="http://www.raywenderlich.com/50319/beginning-auto-layout-tutorial-in-ios-7-part-2">Beginning Auto Layout Tutorial in iOS 7: Part 2</a></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[自定义Container View Controllers]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/07/14/creating-custom-container-view-controllers/"/>
    <updated>2015-07-14T15:14:19+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/07/14/creating-custom-container-view-controllers</id>
    <content type="html"><![CDATA[<p>多数情况下，container view controller 就像普通的view controller。它管理着view，内容，与其他对象协同工作，并且响应在repsonder chain里的事件。</p>

<p>当你设计一个container的时候，你需要显式的在你的container，和它的子controller之间创建父子关系。如下图。注意，<code>不仅仅controller之间需要显式的指定关系，view之间的关系也需要显式的指定</code>。</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-07-14_1.png" width="380"></p>

<!--more-->


<h3>常见的Container设计的例子</h3>

<h4>Navigation Controller管理着一些由子View Controller组成的栈</h4>

<p>如图所示，Navigation Controller管理着一系列不同的子ViewController。在这个栈最上面的ViewController的View会被显示出来。</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-07-14_2.png" width="669"></p>

<p>Navigation Controller定义了一些行为</p>

<ul>
<li>topViewController &ndash; 目前显示的vc</li>
<li>viewControllers &ndash; 所有子vc</li>
<li>pushViewController:animated: &ndash; 显示</li>
<li>popViewControllerAnimated: &ndash; 弹出</li>
<li>delegate &ndash; 可以让使用者当状态改变的时候收到通知</li>
</ul>


<p>Navigation Controller 使用子VC的一些属性来改变当前显示的内容。</p>

<ul>
<li>navigationItem &ndash; 提供了navigation toolbar的内容</li>
<li>toolbarItem &ndash; 提供了底部bar的内容</li>
<li>editButtonItem &ndash; 提供了可以从navigation item访问子view的途径，这样就可以改变子view的edit mode</li>
</ul>


<h4>Tab Bar Controller使用一个子VC的集合</h4>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-07-14_3.png" width="572"></p>

<p>Tab Bar Controller定义了一些行为：</p>

<ul>
<li>viewControllers &ndash; 所有子vc</li>
<li>selectedViewController &ndash; 设置或读取哪个子vc</li>
<li>delegate &ndash; 可以让使用者当状态改变的时候收到通知</li>
</ul>


<p>Tab Bar Controller 使用子VC的一些属性来改变当前显示的内容。</p>

<ul>
<li>tabBarItem &ndash; 提供了底部bar的内容</li>
</ul>


<h4>Page Controller使用DataSource去显示新的子VC</h4>

<p>Page Controller支持无限多的页面显示，所以把所有的page都放在内存中是不可能的。相反，page controller在需要的时候拉取需要的page。这样page controller就使用一个pull model而不是让app把所有的page一下子push到里面</p>

<p>Page Controller定义了一些行为：</p>

<ul>
<li>spineLocation &ndash; 定义page是如何组织的，有时候只显示一个page，有时候需要两个</li>
<li>transitionStyle &ndash; 定义了过场动画的风格</li>
</ul>


<h4>实现自定义Container Controller</h4>

<h5>增加和移除子vc</h5>

<p>始终应该记住的是，在<code>addSubview</code><em>之前</em><code>addChildViewController</code>,在<code>removeFromSuperVieww</code><em>之后</em><code>removeFromParentViewController</code>。</p>

<p>另外，设置子view的大小最好也在addSubview之前</p>

<p>增加</p>

<pre><code>- (void) displayContentController: (UIViewController*) content;
{
    [self addChildViewController:content];                 
    content.view.frame = [self frameForContentController]; 
    [self.view addSubview:self.currentClientView];
    [content didMoveToParentViewController:self];          
}
</code></pre>

<ul>
<li><code>addChildViewController</code>会自动调用<code>willMoveToPa</code></li>
</ul>


<p>移除</p>

<pre><code>- (void) hideContentController: (UIViewController*) content
{
    [content willMoveToParentViewController:nil];  
    [content.view removeFromSuperview];            
    [content removeFromParentViewController];      
}
</code></pre>

<h5>简单的转场动画</h5>

<pre><code>- (void) cycleFromViewController: (UIViewController*) oldC
        toViewController: (UIViewController*) newC
{
    [oldC willMoveToParentViewController:nil];                        
    [self addChildViewController:newC];

    newC.view.frame = [self newViewStartFrame];                       
    CGRect endFrame = [self oldViewEndFrame];

    [self transitionFromViewController: oldC toViewController: newC   
          duration: 0.25 options:0
          animations:^{
             newC.view.frame = oldC.view.frame;                       
             oldC.view.frame = endFrame;
          }
          completion:^(BOOL finished) {
             [oldC removeFromParentViewController];                   
             [newC didMoveToParentViewController:self];
          }];
}
</code></pre>

<h5>自定义显示和旋转的Callback行为</h5>

<p>多数时候不用管这个事情，但是有时候你希望自己控制消息发送的时机之类的情况</p>

<pre><code>- (BOOL) shouldAutomaticallyForwardAppearanceMethods
{
    return NO;
}

-(void) viewWillAppear:(BOOL)animated
{
    [self.child beginAppearanceTransition: YES animated: animated];
}

-(void) viewDidAppear:(BOOL)animated
{
    [self.child endAppearanceTransition];
}

-(void) viewWillDisappear:(BOOL)animated
{
    [self.child beginAppearanceTransition: NO animated: animated];
}

-(void) viewDidDisappear:(BOOL)animated
{
    [self.child endAppearanceTransition];
}
</code></pre>

<p>旋转与显示类似，首先要重载<code>shouldAutomaticallyForwardRotationMethods</code>，然后在合适的地方调用</p>

<ul>
<li><code>willRotateToInterfaceOrientation:duration:</code></li>
<li><code>willAnimateRotationToInterfaceOrientation:duration:</code></li>
<li><code>didRotateFromInterfaceOrientation:</code></li>
</ul>


<h5>Best practices</h5>

<ul>
<li>不要干这事！！因为毕竟实现一个复杂的container不是一件容易的事情</li>
<li>只访问子VC的最顶层的那个View，其他View不要碰！</li>
<li>如果需要子VC暴露一些接口，可以使用protocol！</li>
</ul>


<p>如下</p>

<pre><code>@protocol MyContentContainerProtocol &lt;NSObject&gt;
    ...
@end
- (void) displayContentController: (UIViewController&lt;MyContentContainerProtocol&gt;*) content;
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android中如何使用Messenger]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/07/13/how-to-use-messenger/"/>
    <updated>2015-07-13T14:24:16+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/07/13/how-to-use-messenger</id>
    <content type="html"><![CDATA[<p>&hellip;&hellip;</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[AIDL in Android]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/07/12/aidl-in-android/"/>
    <updated>2015-07-12T13:11:59+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/07/12/aidl-in-android</id>
    <content type="html"><![CDATA[<p>AIDL是用来跨进行通信的。在Android上，跨进程通信需要把对象解构成系统可以识别的基本类型，然后在交给另一个进程使用之前，需要重新组装起来。这些工作是十分枯燥的，AIDL就是为了这个目的而设计的。</p>

<p><code>注意：当且仅当你允许不同的App的clients需要跨进程来访问你的service，并且需要在service里处理多线程问题的时候，你才应该使用AIDL。如果仅仅是App内部的client来访问服务，并且不需要IPC的话，只要使用Binder就好了。如果是需要IPC，但是不用处理并发的话，那么只要用Messager就好了。只有既要IPC，又要处理并发，才需要用AIDL。总之，只有在必须的时候才使用AIDL</code></p>

<!--more-->


<h3>关于AIDL调用的背后</h3>

<p>另一个需要知道的是，AIDL的接口调用是直接调用，所以并不能对调用接口的线程有任何假设。调用的线程在本地进程执行还是在远程进程执行的结果可能是非常不同的。其中：</p>

<ul>
<li>如果是本地进程进行AIDL调用，服务端代码是在进行调用的这个线程中执行的</li>
<li>如果是远程进程进行AIDL调用，你就必须为服务端代码同时在不同线程中执行做好准备，也就是说，这些代码必须是线程安全的</li>
<li><code>oneway</code>关键字用来修饰远调用，使用后表示这个远程调用并不阻塞，它仅仅是发送了数据就立刻返回。而该关键字并不影响本地调用</li>
</ul>


<h3>创建AIDL过程</h3>

<ul>
<li>创建.aidl文件</li>
</ul>


<p>使用Android Studio自己创建IRemoteService.aidl就很好，比如定义接口getPid()</p>

<pre><code>interface IRemoteService {
    int getPid();
}
</code></pre>

<ul>
<li>实现该接口的service</li>
</ul>


<p>例如实现文件AIDLService.java，这个service在onBind函数中返回的binder里含有IRemoteService.aidl定义的接口的实现</p>

<pre><code>public class AIDLService extends Service {

    private final IRemoteService.Stub binder = new IRemoteService.Stub(){

        @Override
        public int getPid() throws RemoteException {
            return android.os.Process.myPid();
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}
</code></pre>

<ul>
<li>使用该AIDL</li>
</ul>


<p>像使用普通service一样</p>

<pre><code>IRemoteService remoteService;

ServiceConnection remoteServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        remoteService = IRemoteService.Stub.asInterface(iBinder);
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        remoteService = null;
    }
};

Intent intent = new Intent(MainActivity.this, AIDLService.class);
bindService(intent, remoteServiceConnection, BIND_AUTO_CREATE);
startService(intent);

int remotePid = remoteService.getPid();
</code></pre>

<h3>在AIDL中传递对象</h3>

<p>比如我们希望AIDL接口可以传递名为Student的对象,需要做以下一些事情</p>

<ul>
<li>定义Student.aidl</li>
</ul>


<p>其中声明Student类型</p>

<pre><code>parcelable Student;
</code></pre>

<ul>
<li>定义aidl接口（IRemoteAPI.aidl）</li>
</ul>


<p>注意要import相应的Student类</p>

<pre><code>import com.morgenworks.alchemistli.remotelibrary.Student;

interface IRemoteAPI {
    Student getName();
    void setName(in Student st);
}
</code></pre>

<ul>
<li>定义实现了Parcelble接口的Student类</li>
</ul>


<p>实现Parcelble接口需要实现这样几个函数, Student(Parcel source), writeToParcel(&hellip;), readescribeContents(), 以及static Creator<Student> CREATOR</p>

<pre><code>public class Student implements Parcelable {
    public String name;
    public String fatherName;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(fatherName);
    }

    public Student(Parcel source){
        name = source.readString();
        fatherName = source.readString();
    }

    public Student(){}

    public void setName(String name){
        this.name = name;
    }

    public void setFatherName(String fatherName){
        this.fatherName = fatherName;
    }

    public static final Creator&lt;Student&gt; CREATOR = new Creator&lt;Student&gt;() {
        @Override
        public Student createFromParcel(Parcel source) {
            return new Student(source);
        }

        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };
}
</code></pre>

<ul>
<li>实现AIDL接口的服务</li>
</ul>


<p>就像实现普通的AIDL接口服务一样</p>

<pre><code>public class RemoteAPIService extends Service {
    private Student stuInfo;

    private IRemoteAPI.Stub binder = new IRemoteAPI.Stub() {
        @Override
        public Student getName() throws RemoteException {
            stuInfo.name = stuInfo.name.toUpperCase();
            return stuInfo;
        }

        @Override
        public void setName(Student st) throws RemoteException {
            stuInfo = st;
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Swift Method]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/06/17/swift-method/"/>
    <updated>2015-06-17T12:42:28+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/06/17/swift-method</id>
    <content type="html"><![CDATA[<p>swift <code>method</code>分为<code>instance method</code>和<code>type method</code></p>

<p><code>instance method</code>是属于实例的函数，<code>type mothod</code>则是属于<code>type</code>的函数</p>

<!--more-->


<h3>Local and External Parameter Names for Method</h3>

<p><code>local and external parameter name</code>的默认行为并不等同于<code>function</code></p>

<p>swift的method的参数名字非常像objective－c。比如说，一般来说，swift的method的名字带有by， with， for等介词，例如incrementBy。</p>

<p>需要指出的是，swift默认会给第一个参数local parameter name，但是对于第二个以后参数则默认生成local and external parameter name。
    class Counter {
        var count : Int = 0
        func incrementBy(amount: Int, numberOfTimes: Int){
            count += amount * numberOfTimes
        }
    }
swift会把amount看作local name，但是会把numberOfTimes看作local and external name。所以调用该method，需要像如下这样
    let counter = Counter()
    counter.incrementBy(5, numberOfTimes: 3)
当然也可以显式的提供第一个参数的external name或者不提供非第一参数的external name
    class Counter2{
        var count : Int = 0
        func incrementBy(#amount: Int, _ numberOfTimes: Int){
            count += amount * numberOfTimes
        }
    }
    let count2 = Count2()
    count2.incrementBy(amount: 5, 3)</p>

<h3>Self Propety</h3>

<p>一般情况下可以不写，但是如果有歧义就需要写
    struct Point{
        var x = 0.0, y = 0.0
        func isToTheRightOfX(x: Double) -> Bool{
            return self.x > x   // must use self
        }
        func description() -> String{
            return &ldquo;x: (x), y: (y)&rdquo;) //no need to use self
        }
    }</p>

<h3>在instance method内改变值类型变量自身</h3>

<p>对于<code>value types</code>来说，一般情况下，instance method不能更改属性，但是加上mutating关键字来改变这点。
    struct Point{
        var x = 0.0, y = 0.0
        mutating func moveByX(deltaX: Double, y deltaY: Double){
            x += deltaX
            y += deltaY
        }
    }</p>

<h3>Assigning to self Within a Mutating Method</h3>

<pre><code>struct Point{
    var x = 0.0, y = 0.0
    mutating func moveByX(deltaX: Double, y deltaY: Double){
        self ＝ Point(x: x+deltaX, y: y + deltaY)
    }
}

enum TriStateSwitch {
    case Off, Low, High
    mutating func next() {
        switch self {
        case Off:
            self = Low
        case Low:
            self = High
        case High:
            self = Off
        }
    }
}
</code></pre>

<h3>Type Method</h3>

<p><code>type method</code>在类中使用关键字<code>class</code>来表示，在结构体和枚举中使用<code>static</code>来表示</p>

<p>在<code>type method</code>中，<code>self</code>表示类型本身，而不是实例本身</p>

<pre><code>​struct​ ​LevelTracker​ {
​    ​static​ ​var​ ​highestUnlockedLevel​ = ​1
​    ​static​ ​func​ ​unlockLevel​(​level​: ​Int​) {
​        ​if​ ​level​ &gt; ​highestUnlockedLevel​ { ​highestUnlockedLevel​ = ​level​ }
​    }
​    ​static​ ​func​ ​levelIsUnlocked​(​level​: ​Int​) -&gt; ​Bool​ {
​        ​return​ ​level​ &lt;= ​highestUnlockedLevel
​    }
​    ​var​ ​currentLevel​ = ​1
​    ​mutating​ ​func​ ​advanceToLevel​(​level​: ​Int​) -&gt; ​Bool​ {
​        ​if​ ​LevelTracker​.​levelIsUnlocked​(​level​) {
​            ​currentLevel​ = ​level
​            ​return​ ​true
​        } ​else​ {
​            ​return​ ​false
​        }
​    }
​}
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Swift Optional Chaining]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/06/17/swift-optional-chaining/"/>
    <updated>2015-06-17T09:19:59+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/06/17/swift-optional-chaining</id>
    <content type="html"><![CDATA[<p><code>optinal chainging</code>是一个查询和调用<code>optional</code>的property, method, subscript的过程。如果其中的<code>optional</code>没有nil，那么表达式求值成功。否则，失败。失败后返回nil。所以整个表达式返回值始终是<code>optional</code>类型。</p>

<!--more-->


<p>以下是一些sample code, 先构造一些类</p>

<pre><code>class Person{ var residence: Residence? }

class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int { return rooms.count }

    subscript(i: Int) -&gt; Room {
        get { return rooms[i] }
        set { rooms[i] = newValue }
    }

    func printNumberOfRooms(){
        println("The number of rooms is \(numberOfRooms)")
    }
}

class Room {
    let name: String
    init(name: String){ self.name = name }
}

class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?

    func buildingIdentifier() -&gt; String? {
        if buildingName != nil {
            return buildingName
        } else if buildNumber != nil {
            return buldingNumber
        } else {
            return nil
        }
    }
}
</code></pre>

<p>下面就是如何使用<code>optional chain</code></p>

<pre><code>let john = Person()
if let roomCount = john.residence?.numberOfRooms {
    println("john's residence has \(roomCount) rooms.")
}
// will print nothing

let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress //will fail
</code></pre>

<p>Residence里的方法printNumberOfRooms()没有返回值，但是这意味着该方法返回类型是Void，也就是返回值是(),也就是一个空的tuple. 在<code>optional chain</code>里，会返回Void?</p>

<pre><code>if john.residence?.printNumberOfRoom() != nil {
    println("It was possible to print the number of rooms."
} 
// will print nothing
</code></pre>

<p>对于通过<code>optional chain</code>来设置属性也一样</p>

<pre><code>if (john.residence?.address = someAddress) != nil {
    println("It was possible to set the address."
}
// will print nothing
</code></pre>

<p>通过<code>optional chaining</code>访问subscript</p>

<pre><code>if let firstRoomName = john.residence?[0].name {
    println("the first room name is \(firstRoomName)")
}
// will print nothing

let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "Living Room"))
johnsHouse.rooms.append(Room(name: "Kitchen"))
john.residence = johnsHouse

if let firstRoomName = john.residence?[0].name {
    println("the first room name is \(firstRoomName)")
}
// prints "the first room name is Living Room"
</code></pre>

<p>访问<code>optional</code>的subscript</p>

<pre><code>var testScrores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0]++
testScores["Brain"]?[0]
</code></pre>

<p>多层的optional chain， 原则是
* 如果试图查询的东西的类型并非是<code>optional</code>的，会由于使用了chain而变成<code>optional</code>
* 如果正在查询的东西已经是<code>optional</code>的，它不会因为chain变得“更”<code>optional</code>（<code>optional</code>的<code>optional</code>)</p>

<p>下面是代码示例</p>

<pre><code>if let johnsStreet = john.residence?.address?.street{
    println("John's street name is \(johnsStreet)")
}
// print nothing

let johnsAddress = Address()
johnsAddress.buildingName = "The Larches"
johnsAddress.street = "Laurel Street"
john.residence?.address = johnsAddress

if let johnsStreet = john.residence?.address?.street{
    println("John's street name is \(johnsStreet)")
}
// print "John's street name is Laurel Street"

if let beginsWithThe = john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
    if beginWithThe {
        println("John's building identifier begins with \"The\".")
    }
}
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Swift Extension]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/06/17/swift-extension/"/>
    <updated>2015-06-17T07:45:07+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/06/17/swift-extension</id>
    <content type="html"><![CDATA[<p><code>extensions</code>可以给已有的type增加功能，而且不必访问源代码(<code>retroactive modeling</code>)</p>

<p><code>extensions</code>可以</p>

<ul>
<li>增加<code>computed property</code>和<code>computed static property</code></li>
<li>定义<code>instance methods</code>和<code>type methods</code></li>
<li>提供新的<code>initializers</code></li>
<li>定义<code>subscripts</code></li>
<li>定义和使用新的<code>nested types</code></li>
<li>为一个<code>type</code>实现一个<code>protocol</code></li>
</ul>


<p><code>extension</code>不可以</p>

<ul>
<li><code>extension</code>可以增加新的<code>funtionality</code>，但是不能覆盖以有的<code>functionality</code></li>
<li><code>extension</code>不能增加<code>stored properties</code>，或者给存在的<code>property</code>增加<code>property observers</code></li>
<li><code>extension</code>不能增加新的<code>designated initializer</code></li>
</ul>


<!--more-->


<h4>Extension 语法</h4>

<pre><code>extension SomeType {
    ...
}

extiosion SomeType: Someprotocol, AnotherProtocol {
    ...
}
</code></pre>

<p>一个有趣的例子</p>

<pre><code>extension Double {
    var km: Double { return self * 1000.0 }
    var m: Double { return self }
}

let aMarathon = 42.m + 195.m
println("A marathon is \(aMarathon) masters long")
</code></pre>

<h4>Initializers</h4>

<pre><code>struct Size { var width = 0.0, height = 0.0 }
struct Point { var x = 0.0, y = 0.0 }
struct Rect {
    var origin = Point()
    var size = Size()
}

extension Rect{
    init(center: Point, size: Size){
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x:originX, y:originY), size: size)
    }
}
</code></pre>

<h4>Methods</h4>

<pre><code>extension Int{
    func repetitions(task: ()-&gt; ()){
        for i in 0..&lt;self {
            task()
        }
    }
}

3.repetitions{ println("hello") }
</code></pre>

<h4>Mutating Instance Methods</h4>

<pre><code>extension Int {
    mutating func square(){
        self = self * self
    }
}

var someInt = 3.square()
</code></pre>

<h4>Subscripts</h4>

<pre><code>extension Int {
    subscript(var digitIndex: Int) -&gt; Int{
        var decimalBase = 1
        while digitIndex &gt; 0 {
            decimalBase *= 10
            --digitIndex
        }

        return (self / decimalBase) % 10
    }
}

74631295[1] //return 9
</code></pre>

<h4>Nested Tyeps</h4>

<pre><code>extension Int {
    enum Kind {
        case Negative, Zero, Positive
    }

    var kind: Kind {
        switch self {
        case 0: retrun .Zero
        case let x where x &gt; 0: return .Positive
        default: return .Negative
        }
    }
}
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Swift中optional]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/06/12/swift-optional/"/>
    <updated>2015-06-12T15:37:14+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/06/12/swift-optional</id>
    <content type="html"><![CDATA[<p>关于<code>optional</code>，最需要说的是为什么需要<code>optional</code>，比如说在objctive-c中就没有，也是可以表示一个不存在的对象的。只需要用NULL就可以了。但是如何表示一个不存在的value类型的变量呢？比如一个不存在的struture？objective-c就没有太好的办法了，一般来说是用一个特殊值NSNotFound来表示。不过swift可以让一切不存在的变量都为nil，这就是<code>optional</code>的目的</p>

<!--more-->


<p>关于<code>optional</code>，剩下的只是swift里面有关的特殊术语，搞清楚还是很有必要的</p>

<h4>Force Unwrapping</h4>

<p><code>Force Unwarpping</code>指的是把<code>optional</code>对象转化成一个非空的对象</p>

<h4>Optional Binding</h4>

<p>其基本形式是</p>

<pre><code>if let constantName = someOptional

while let constantName = someOptional
</code></pre>

<h4>Implicity Unwrapped Optionals</h4>

<p>一个optinal变量可以定义为<code>implicity unwrapped optionals</code>, 那么使用这个变量的时候就不再需要force unwrap, 一旦unwrap失败，程序会崩溃</p>

<pre><code>var storyboardName : String! = "hello"
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Swift中的类型转换]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/06/11/typecastinginswift/"/>
    <updated>2015-06-11T11:34:01+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/06/11/typecastinginswift</id>
    <content type="html"><![CDATA[<p>Swift中使用<code>as</code>和<code>is</code>运算符来进行类型转换</p>

<!--more-->


<h4>一个类继承的例子</h4>

<pre><code>class MediaItem{
}

class Movie: MediaItem{
    var director : String
    init(director: String){ self.director = director; super.init() }

}

class Song: MediaItem{
    var artist : String
    init(artist: String){ self.artist = artist; super.init() }
}
</code></pre>

<h4>类型检查使用<code>is</code></h4>

<pre><code>let library = [Movie("d1"), Song("a1"), Song("a2"), Movie("d2")]

var movieCount = 0
var songCount = 0

for item in library {
    if item as Movie {
        ++movieCount
    } else if item is Song {
        ++songCount
    }
}
</code></pre>

<p>值得一提的是，<code>is</code>不仅仅用来检测有继承关系的类，而且可以用来检测是否实现了某个接口</p>

<pre><code>protocal HasArea{
    var area: Double { get }
}

class Circle: HasArea{
    var radius: Double
    var area: Double { return 3.14 * radius * radius }
    init(radius: Double){ self.radius = radius }
}

var circle = Circle(2.5)
if circle is HasArea {
    println("Area: \(circle.area)")
}
</code></pre>

<h4>类型转换</h4>

<p>可以使用<code>as</code>来进行类型转换</p>

<p>可以用两种方式来使用<code>as</code>, <code>as?</code>和<code>as!</code></p>

<p><code>as?</code>表示不确定该转换是否能成功，<code>as!</code>表示一定会成功，但是如果运行时转换失败的话，程序会崩掉</p>

<pre><code>for item in library {
    if let movie = item as? Movie {
        println("Director: \(movie.director)")
    } else if let song = item as? Song {
        println("Artist: \(song.artist)")
    }
}
</code></pre>

<h4><code>Any</code>和<code>AnyObject</code>的类型转换</h4>

<p>其实，<code>Any</code>和<code>AnyObject</code>的转换和普通的类型转换是一样的。值得说的是为什么swift要有他们两个。</p>

<ul>
<li><code>AnyObject</code>可以代表任何class类型的实例</li>
<li><code>Any</code>却可以代表任何类型的实例，包括funtion类型</li>
</ul>


<p>举两个例子，第一个例子</p>

<pre><code>let someObjects: [AnyObject] = [Movie('d1'),Movie('d1'),Movie('d1')]
for object in someObjects{
    let movie = object as! Movie
    println("Movie director: \(movie.director)")
}
</code></pre>

<p>该例子中，还可以直接cast整个数组</p>

<pre><code>for movie in someObjects as! [Movie] {
    println("Movie director: \(movie.director)")
}
</code></pre>

<p>另外一个是关于<code>Any</code>的例子</p>

<pre><code>var things = [Any]()

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie("d1"))
things.append({(name: String) -&gt; String in 
    "Hello, \(name)" })

for thing in things{
    switch thing{
        case 0 as Int: 
            println("zero as an Int")
        case 0 as Double:
            println("zero as an Double")
        case let someInt as Int:
            println("an integer value of \(someInt)")
        case let someDouble as Double where someDouble &gt; 0:
            println("a positive double : \(someDouble)")
        case is Double:
            println("some other double value &lt;= 0")
        case let someString as String:
            println("a string value : \(someString)")
        case let (x, y) as (Double, Double) :
            println("an (x,y) point at \(x), \(y)")
        case let movie as Movie:
            println("a movie director: \(movie.director)")
        case let stringConverter as String -&gt; String:
            println(stringConverter("Michael")
        default:
            println("something else")
    }
}
</code></pre>

<p>需要指出，在switch的case语句中，使用的<code>as</code>是强制转换版的，并不写作<code>as?</code>或者<code>as!</code>，在case语句中使用这种检查总是安全的。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Swift Initialization]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/06/10/swift-initialization/"/>
    <updated>2015-06-10T11:22:46+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/06/10/swift-initialization</id>
    <content type="html"><![CDATA[<h3>swift的初始化</h3>

<p>这里不是要权威的解释initilization，而是想总结一些swift initilizer的特点</p>

<!--more-->


<p>初始化发生在<em>class</em>, <em>structure</em>, <em>enumeration</em>初始准备的过程中。coder可以通过定义<em>initializers</em>来实现初始化。值得注意的是，<em>initializers</em>没有返回值。</p>

<p>此外，class还可以实现一个&#8217;deinitializer&#8217;</p>

<h3>如何定义initializer</h3>

<p>定义initializer需要用关键字<em>init</em></p>

<h3>Simplest initializer</h3>

<pre><code>struct Fahrenhit{
    var temperature: Double
    init(){
        temperature = 32.0
    }
}
</code></pre>

<h3>自定义initializer</h3>

<p>可以使用initializer parameters来自定义initializer</p>

<pre><code>struct Celsius{
    var temperatureInCelsius: Double
    init(fromFahrenhit fahrenhit: Double){
        temperatureInCelsius = (fahrenhit - 32.0)/1.8
    }
    init(fromKelvin kelvin: Double){
        temperatureInCelsius = kelvin - 273.15
    }
}
</code></pre>

<h3>调用initializer</h3>

<p>由于initializer每个参数默认有external name，所以调用的时候一定要写external name</p>

<pre><code>let boilingPoint = Celsius(fromFahrenhit: 212.0)
let freezePoint = Celsius(fromKelvin: 273.15)
</code></pre>

<h3>Default initializer</h3>

<ul>
<li><p>如果structure或者base class没有提供initializer的话，编译器会提供一个默认的init()。</p></li>
<li><p>对于structure来说如果没有任何自定义的initializer的话，编译器会还会提供一个memberwise initializer</p></li>
</ul>


<h3>Initializer Delegation</h3>

<ul>
<li>value类型和class类型的initilizer delegation的规则是不同的</li>
</ul>


<h3>Structure和Enumunation的Intializer Delegation</h3>

<ul>
<li>只能在initializer中调用self.init</li>
</ul>


<h3>Class Inheriantance and Initialization</h3>

<p>class的initializer分为Designated initializer和Convenience initializer</p>

<h4>Designated initializer和Convenience initializer</h4>

<p>Designated initializer是primary initializer，每个class只要要有一个</p>

<pre><code>init(parameters) { statements }
</code></pre>

<p>Convenience initializer是为了方便而存在的，需要通过Designated initializer来初始化，关键字为<em>convenience</em></p>

<pre><code>convenience init(parameters){ statements }
</code></pre>

<h4>Initializer Delegattion for Class Types</h4>

<ul>
<li>Rule1 一个designated initializer必须调用它直接父类的designated initializer</li>
<li>Rule2 一个convenience initializer必须调用它自己的另一个initializer</li>
<li>Rule3 一个convenience initializer必须最终调用它自己的designated initializer</li>
</ul>


<p>可以简单总结为</p>

<ul>
<li>designated initializer必须delegate up</li>
<li>convenience initializer必须delegate across</li>
</ul>


<p>可以看下图</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-10_1.png" width="600"></p>

<p>下面是一个更复杂的例子</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-10_2.png" width="600"></p>

<h4>两阶段的初始化</h4>

<p>在初始化过程中，首先所有的类属性都会被赋予初始值，当这一阶段完成之后，然后在被initializer里代码设置其值<br/>
关于这点，swift的编译器会进行一些检查</p>

<ul>
<li><p>safety check 1 : designated initializer在delegates up到superclass initializer之前，必须保证所有属性都被初始化了</p></li>
<li><p>safety check 2 : designated initializer必须先delegate up到superclass initializer才能赋值给继承下来的属性</p></li>
<li><p>safety check 3 : convenience initializer必须先delegate到其他initializer才能修改属性</p></li>
<li><p>safety check 4 : initializer需要第一阶段初始化完成才能修改属性，调用成员方法</p></li>
</ul>


<p>两阶段初始化的具体过程不详细说了，需要知道的是，当内存分配好之后，先由子类的initializer负责初始化自己的属性，然后向上传递控制权，父类做相同的事情，直到根基类。这时候第一阶段初始化就完成了。第二阶段初始化是从顶向下进行，这时候self就可以访问了，同时可以修改访问self的属性了，调用成员函数了。</p>

<h5>第一阶段初始化</h5>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-10_3.png" width="600"></p>

<h5>第二阶段初始化</h5>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-10_4.png" width="600"></p>

<h4>Initializer的Inheritance和Override</h4>

<p>原则上，swift不允许initializer继承，但是在下列情况下可以继承</p>

<ul>
<li><p>如果子类没有写任何designated initializer，子类可以继承所有父类的designated initializer</p></li>
<li><p>如果子类提供了所有父类的designated initializer的实现－－无论是继承而来的，还是自己override的，那么自动继承所有的父类的convenience initializer</p></li>
</ul>


<p>下面举个例子：</p>

<pre><code>class Food{
    var name : String
    init(name: String){ self.name = name }
    convenience init() { self.init(name: "[Unnamed]") }
}
</code></pre>

<p>下图显示了initializer chain</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-10_5.png" width="600"></p>

<pre><code>class RecipeIngredient: Food{
    var quantity : Int
    init(name: String, quantity: Int){
        self.quantity = quantity
        super.init(name: name)
    }
    override convenience init(name: String){
        self.init(name: name, quantity: 1)
    }
}
</code></pre>

<p>initializer chain如图</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-10_6.png" width="600"></p>

<pre><code>class ShoppingListItem: RecipeIngredient {
    var purchased = false
    var description: String {
        var output = "\(quantity) x \(name)"
        output += purchased ? "OK" : "Not"
        return output
    }
}
</code></pre>

<p>initializer chain如图</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-10_7.png" width="600"></p>

<h4>Failable Initializer</h4>

<p>语法如下</p>

<pre><code>init?(parameters){ statments }
</code></pre>

<p>举个例子来说
    struct Animal{
        let species: String
        init?(species: String){
            if species.isEmpty { return nil }
            self.species = species
        }
    }</p>

<p>通过<em>return nil</em>，我们可以表示初始化失败</p>

<p>可以像如下方式来使用
    let someCreature = Animal(species: &ldquo;&rdquo;)
    if let griaffe = someCreature{ println(&ldquo;no species&rdquo;) }</p>

<h4>Failable Initializer for Enumerations</h4>

<pre><code>enum TemperatureUnit{
    case Kelvin, Celsius, Fahrenheit
    init?(symbol: Character){
        switch symbol{
        case "K": self = .Kelvin
        case "C": self = .Celsius
        case "K": self = .Fahrenheit
        default:
            return nil
        }
    }
}


if let unknowUnit = TemperatureUnit("X") { println("no such unit") }
</code></pre>

<h4>Automatic Failable Initializer for Enumerations with Raw Value</h4>

<pre><code>enum TemperatureUnit : Character{
    case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}

if let unknowUnit = TemperatureUnit("D"){ println ("no such unit") }
</code></pre>

<h4>Failable Initializer for Classes &amp; Propagation of Initialization Failure</h4>

<p>对于类来说，初始化失败只能在所有属性都已经被设置了初始值之后发生</p>

<pre><code>class Product{
    let name: String!
    init?(name: String){
        self.name = name
        if name.isEmpty { return nil }
    }
}

class CartItem: Product{
    let quantity: Int!
    init?(name: String, quantity: Int){
        self.quantity = quantity
        super.init(name: name)
        if(quantity &lt; 1) { return nil }
    }
}
</code></pre>

<h4>Override a Failable Initializer</h4>

<p>你可以使用non-failable initializer去override父类的failable initializer，但这时就不能再delegate up到failable initilizer</p>

<pre><code>class Document{
    var name: String?
    init() {}
    init?(name: String){
        self.name = name
        if name.isEmpty { return nil }
    }
}

class AutomaticallyNamedDocument: Document{
    override init(){ 
        super.init()
        self.name = "[Untitled]"
    }
    override init(name: String){
        super.init()
        if name.isEmpty{ 
            self.name = "[Untitled]"
        }
        else{ 
            self.name = name 
        }
    }
}
</code></pre>

<h4>Required Initializer</h4>

<p><em>required</em> modifier表示该类的每一个子类都必须实现这个initilizer<br/>
在子类实现该initializer时候必须也添加<em>required</em></p>

<pre><code>class SomeClass{
    required init(){ ... }
}

class SomeSubClass{
    required init(){ ... }
}
</code></pre>

<h4>Setting a Default Property Value with a Closure or Function</h4>

<pre><code>class SomeClass{
    let someProperty: SomeType = {
        return someValue
    }()
}
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用swift生成Frameworks]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/06/09/shi-yong-swiftsheng-cheng-frameworks/"/>
    <updated>2015-06-09T19:04:02+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/06/09/shi-yong-swiftsheng-cheng-frameworks</id>
    <content type="html"><![CDATA[<h3>制作Dynamically Linked Frameworks</h3>

<!--more-->


<h3>一个普通的Swift file</h3>

<pre><code>class SwiftFrameworks {
    init() { println("Class init") }
    func doSomething() { println("Yeah, it works") }
} 
</code></pre>

<p>为了让它可以在framework中工作，需要让所有类和方法都是<em>public</em>的</p>

<pre><code>public class SwiftFrameworks { 
    public init() { println("Class init") } 
    public func doSomething() { println("Yeah, it works") } 
} 
</code></pre>

<h3>建立framework工程</h3>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-09_1.png" width="600"></p>

<h3>添加刚才的swift文件</h3>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-09_4.png" width="600"></p>

<h3>编译</h3>

<p>有时候编译时候并不能产生target，切换一下设备（可能是xcode的bug），然后找到build好的target所在文件夹</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-09_2.png" width="600"></p>

<h3>添加到测试工程中</h3>

<p>把编译好的framework拖拽到测试工程中，之后在embed中添加该framework</p>

<p><img class="center" src="http://IamAlchemist.github.io/images/iOS/2015-06-09_3.png" width="600"></p>

<p>然后</p>

<pre><code>import SwiftFramework
let swiftFramework = SwiftFramework()
swiftFramework.helloWorld()
</code></pre>

<p>大功告成～</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Memory Churn]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/05/06/memory-churn/"/>
    <updated>2015-05-06T13:46:43+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/05/06/memory-churn</id>
    <content type="html"><![CDATA[
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android Preformace 2: Detect Memory Leak]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/05/05/android-preformace-2-detect-memory-leak/"/>
    <updated>2015-05-05T20:42:43+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/05/05/android-preformace-2-detect-memory-leak</id>
    <content type="html"><![CDATA[<h3>the common way to detect memory leak</h3>

<!--more-->


<ul>
<li>use Heap tool and Allocation tracing</li>
<li>start a empty activity</li>
<li>jump to the activity in question</li>
<li>trigger gc</li>
<li>watch the heap</li>
</ul>


<p><img class="center" src="http://IamAlchemist.github.io/images/android_performace/memory_leak_detection.png" width="600"></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android Performance 1: Memory Monitor]]></title>
    <link href="http://IamAlchemist.github.io/blog/2015/05/04/android-performance-patther-1/"/>
    <updated>2015-05-04T20:32:24+08:00</updated>
    <id>http://IamAlchemist.github.io/blog/2015/05/04/android-performance-patther-1</id>
    <content type="html"><![CDATA[<h3>android studio can trace the general memory usage by <em>Memory Moniter</em></h3>

<!--more-->


<p>android studio can trace the general memory usage by <em>Memory Moniter</em><br/>
<img class="center" src="http://IamAlchemist.github.io/images/android_performace/memory_moniter.jpg" width="500"></p>

<p>watch the video <a href="https://www.youtube.com/watch?v=7ls28uGMBEs&amp;list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&amp;index=36">here</a></p>
]]></content>
  </entry>
  
</feed>
