<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Nico</title>
 <link href="http://blog.inico.me/" rel="self"/>
 <link href="http://blog.inico.me"/>
 <updated>2020-06-15T15:15:18+00:00</updated>
 <id>http://blog.inico.me</id>
 <author>
   <name>Nicholas Tau</name>
   <email>hi@inico.com</email>
 </author>

 
 <entry>
   <title>哥哥我的头发又回来啦</title>
   <link href="http://blog.inico.me/2017/11/27/hair-loss-Minoxidil-Finasteride"/>
   <updated>2017-11-27T21:30:00+00:00</updated>
   <id>http://blog.inico.me/2017/11/27/hair-loss Minoxidil Finasteride</id>
   <content type="html">&lt;p&gt;以下内容均为本人真实经历，照片文字均为本人真实拍摄。未经允许不得转载。先给大家看一下我进行脱发治疗前的照片，所谓有图有真相。看完之后有兴趣的可以继续往下看文章正文。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demonnico/demonnico.github.com/master/_images/CED70066-F6B4-4C5C-9743-984388BE9CE5-18389-00000A4E378424C5_tmp_A.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demonnico/demonnico.github.com/master/_images/CED70066-F6B4-4C5C-9743-984388BE9CE5-18389-00000A4E378424C5_tmp_b.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;图片拍摄于2017年7月左右，触目惊心对不对？&lt;/p&gt;

&lt;p&gt;说到脱发问题，在我所接触的这个行业里的从业人员中，应该是非常常见的，特别是在男性中。在一般人的眼中，男性发生脱发的年龄段可能会在 40 周岁左右，但我自己最早意识到自己有脱发问题的时候，差不多是在4年前。本人目前 30 周岁，家族中没有脱发史。所以也就是26岁左右的时候。&lt;/p&gt;

&lt;p&gt;记得那段时间工作压力比较大，然后家里又开始催着终生大事，每天都很晚才睡着。上床很早，但入睡很晚，躺在床上越焦虑越睡不着。睡着后头皮又特别痒(不是我不洗头，我是属于基本上每天洗的那种)，受不了就开始挠头，第二天起来就会在床头看到一堆头发。&lt;/p&gt;

&lt;p&gt;这种情况大概持续了两年多，其间自己各种了解关于治疗脱发的药物。从自己的搜索和总结来看，目前被认为安全的有两种药物：外用&lt;a href=&quot;https://zh.wikipedia.org/zh-hans/%E7%B1%B3%E8%AF%BA%E5%9C%B0%E5%B0%94&quot;&gt;米诺地尔 (Minoxidil) 5%溶度&lt;/a&gt; 内服&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E9%9D%9E%E9%82%A3%E6%96%AF%E7%89%B9%E8%8E%B1&quot;&gt;非那雄胺 Finasteride Tablets 1mg&lt;/a&gt;(这两种成分是药物中产生药效的主要成分，市面上有很多治疗脱发的药品主要成分都是这两类)。这段时间应该都是处于不断积累脱发知识的阶段，但都没有实践。主要还是担心网上传的一些关于这类药物的副作用：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;米诺地尔：可能存在的不良反应即应用部位发生干燥、脱屑、痒及发红。因为米诺地尔擦剂中的酒精和丙二醇可能会使头皮干燥，造成头皮屑和接触性皮肤炎。也有人通过使用 2% 浓度的米诺地尔溶液来改善过敏反应。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;非那雄胺：根据 &lt;a href=&quot;https://www.accessdata.fda.gov/drugsatfda_docs/nda/2012/020788Orig1s020.pdf&quot;&gt;FDA 的报告&lt;/a&gt;来看，在用药(1mg剂量) 945 人持续用药一年(对照组 934 人)后，集中的一些副作用包括：性欲减退(用药组1.8%，安慰剂对照组1.3%)、勃起障碍(用药组1.3%，安慰剂对照组0.7%)、射精减少(用药组1.2%，安慰剂对照组0.7%)。在中止用药后这些不良反应消失，也有部分患者在继续用药的过程中不良反应消失。在持续用药五年的患者中，上述不良反应率减少(小于等于0.3%)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;直到有一天(15年夏天)，早起刷牙照镜子的时候，终于意识到了问题的严重性(发际线呢？我的发际线呢？感觉自己要慢慢回到清朝了)。于是就抽空去了本地一家以皮肤科著名的医院，挂了脱发专科。当时记得医生给我验血，查了血常规和性激素指标，印象中比正常范围高了很多， 因此确定我是属于&lt;a href=&quot;https://www.zhihu.com/question/25747400&quot;&gt;雄性脱发&lt;/a&gt;，而且属于早期。在用药选择上当时我选择了保守的外用 米诺地尔(5%)。主要还是担心副作用。但医生说这个效果会比较慢，可能要三个月左右才能起效，每天早晚都得用药。那会儿觉得没啥问题，一定能坚持用药。但事实上自己在用了一个月的时候发现没啥明显效果(的确效果很慢)，就主动弃疗了。&lt;/p&gt;

&lt;p&gt;然后就是又过了大概一年多(17年夏天)，自己翻到手机里一年前拍的照片，对比现在发际线之后被吓到了。于是又重新开始用药，这次我除了外用米诺地尔之外，又内服了非那雄胺(自己也是在考虑了很久之后才用，即使上文中提到有小概率出现副作用，但是这仍然是目前 FDA 批准的唯一口服有效的雄性激素脱发治疗药物，而且安慰剂组和用药组的数据相差并不是特别大。事实证明自己的这个决定是正确的:P)。到目前为止坚持了大概四个月，可以用四个字形容：效果显著！！！&lt;/p&gt;

&lt;p&gt;一图胜千言(右图拍摄于三周前，2017年11月初)：
&lt;img src=&quot;https://raw.githubusercontent.com/demonnico/demonnico.github.com/master/_images/CED70066-F6B4-4C5C-9743-984388BE9CE5-18389-00000A4E378424C5_tmp_compare.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;最后想说的是：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;市面上生发产品琳琅满目，但公认安全的不多。能写清主要有效成分并做过双盲实验的，更是寥寥无几&lt;/li&gt;
  &lt;li&gt;非那雄胺(1mg，记住是 1mg！因为 5mg 的药主要是用于治疗前列腺的。。。)只适用于男性。如果你有生育的打算，至少提前半年停止用药(医生告诉我的)。用药前遵医嘱，我虽然查了很多资料，但毕竟不是医生&lt;/li&gt;
  &lt;li&gt;米诺地尔酊属于 OTC 药物，国内药店(x宝)都可以买到。但据说这种药&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E7%B1%B3%E8%AF%BA%E5%9C%B0%E5%B0%94&quot;&gt;对猫致命&lt;/a&gt;。。。所以如果你家养猫，记得放好。用完记得把手洗干净&lt;/li&gt;
  &lt;li&gt;”xx偏方有效，xx中药有效，我家隔壁的王老二就是怎么治好的！”不好意思，咱们不是一路人&lt;/li&gt;
  &lt;li&gt;本文仅针对自己的生发经历作为总结，不作为任何人用药参考。决定用药前请确保你是能为自己决定负责的成年人&lt;/li&gt;
  &lt;li&gt;到发稿目前为止，本人没有出现任何明显的副作用&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demonnico/demonnico.github.com/master/_images/CED70066-F6B4-4C5C-9743-984388BE9CE5-18389-00000A4E378424C5_C.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;发稿前一分钟拍摄。&lt;/p&gt;

&lt;p&gt;本文中所有资料查询来自 Google，知乎。另附几篇知乎中关于脱发知识的问答&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/question/37273041&quot;&gt;脱发，有什么好的改善方法吗？&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/question/26475577&quot;&gt;非那雄胺、米诺地尔副作用大吗？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>Kotlin的黑魔法</title>
   <link href="http://blog.inico.me/2016/10/26/Kotlin-Magic-Java-Swift"/>
   <updated>2016-10-26T22:05:00+00:00</updated>
   <id>http://blog.inico.me/2016/10/26/Kotlin Magic Java Swift</id>
   <content type="html">&lt;p&gt;本人目前主要做 iOS 相关的开发工作，但在做 iOS 之前曾经用 Java 写过一些 Android 上的应用，所以基本上算是个半吊子的 Android 开发工程师。在经历 Swift 的洗礼之后，看到 Kotlin 就感觉看到了久违的朋友一般。在这里我会结合自己的一些感受，以及之前在线下开发者分享会的时候整理的资料，说一下自己的一些心得体会。希望可以给想了解这门语言的同学带来一些帮助和新的启发。&lt;/p&gt;

&lt;p&gt;这篇文章不会对 Kotlin 的语法细节进行讨论，我会通过一些代码片段对比Kotlin、Swift、和Java，之后重点会对 Kotlin 中的Delegated properties(属性委托，Kotlin中许多重要的特性都是基于该特性)进行说明，最后再进行简单的总结。&lt;/p&gt;

&lt;h1 id=&quot;javakotlinswift都拉出来溜溜&quot;&gt;Java、Kotlin、Swift，都拉出来溜溜&lt;/h1&gt;

&lt;p&gt;我们先来看一段Java代码&lt;/p&gt;

&lt;h2 id=&quot;java&quot;&gt;Java&lt;/h2&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Student&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Student&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Student&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;gender&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bodyHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;nc&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HashMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;email&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bodyHeight&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bodyHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBodyHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bodyHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setBodyHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bodyHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bodyHeight&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bodyHeight&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getGender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setGender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;gender&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getEmail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setEmail&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getAge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setAge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;上面这段代码非常简单，我们声明了一个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Student&lt;/code&gt;的类，它有两个构造方法，分别是单参和多参，为了控制访问，我们需要对所有的成员变量设置&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getter&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setter&lt;/code&gt;，这种做法在Java代码里应该已经司空见惯了。为了方便调试，我们重写了&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toString&lt;/code&gt;方法，如果调用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toString&lt;/code&gt;则会把当前对象的一些基本信息作为字符串返回。&lt;/p&gt;

&lt;p&gt;接下来我们可以看一下在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;下的实现：&lt;/p&gt;

&lt;h2 id=&quot;kotlin&quot;&gt;Kotlin&lt;/h2&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//kotlin特有的构造方法声明语法&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//I’m property, not a member or field&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//支持optional类型&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;lateinit&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;isBoy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;lazy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;//如果需要声明构造方法，需要使用constructor关键字&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
		 &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;
		 &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;
		 &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;bodyHeight&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0f&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;   

	&lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mapOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
		&lt;span class=&quot;s&quot;&gt;&quot;email&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;age&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
		&lt;span class=&quot;s&quot;&gt;&quot;bodyHeight&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bodyHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;不熟悉的同学可能会疑惑，在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;下&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getter&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setter&lt;/code&gt;都去了哪里？不用担心，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;并没有帮我们把访问限制去掉。只是我们在编码的时候不用在代码显式地写出来(你说这些都可以用快捷键自动生成啊？好吧我承认这位同学你的代码量比我的又多了不少，我认输。。。)。如果需要添加自己的访问控制的时候才需要进行声明。&lt;/p&gt;

&lt;p&gt;还有一个需要提到很重要的特性的是，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;支持 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;懒加载&lt;/code&gt;。也就是说当某些成员被声明为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lazy&lt;/code&gt;的时候，他们只在第一次被访问的时候才进行初始化。设想一下，在Java中我们需要写自己的懒加载逻辑，而在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;里在语法中就原生支持了这个现代语言特性。&lt;/p&gt;

&lt;p&gt;除了上文中提到的这些，作为一个现代的语言，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;强大的类型推导虽然算不上什么新鲜玩意儿，但在使用的时候也是功不可没。比如我们在初始化变量的时候如果直接进行赋值，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var email = ”hello@alipay.com“&lt;/code&gt;，那么&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt;在被编译的时候会自动声明为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt;类型。在成功安装&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;的插件之后，在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Android Studio&lt;/code&gt;下通过&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tool-&amp;gt;Kotlin-&amp;gt;Show Kotlin Bytecode&lt;/code&gt; ：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/demonnico/demonnico.github.com/raw/master/_images/b8c54f019fcf86ce426bb11979ba79b5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;我们可以轻松看到&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;其实在编译成&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class&lt;/code&gt;的时候和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Java&lt;/code&gt;并无差异，但是由于我们在编码的时候因为使用了&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;，生产力大大提升。&lt;/p&gt;

&lt;p&gt;最后出场的是Swift&lt;/p&gt;

&lt;h2 id=&quot;swift&quot;&gt;Swift&lt;/h2&gt;

&lt;div class=&quot;language-swift highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Student&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;age&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;gender&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;lazy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;isBoy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bodyHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;_bodyHeight&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newValue&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_bodyHeight&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;convenience&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bodyHeight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;从语法特征来看，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Swift&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;简直神似。但如果正真使用过这两种语言编码之后，我发现&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;在类型推导上做得更好。在声明一些闭包类型的时候，我就遇到过在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;语义下是可以被识别的而在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Swift&lt;/code&gt;下无法编译通过的例子。这也是我在用这两种语言做业务开发过程中遇到过最为头疼的事。&lt;/p&gt;

&lt;p&gt;接下就让我们一起来看看&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;里有哪些黑魔法吧。&lt;/p&gt;

&lt;h1 id=&quot;黑魔法篇&quot;&gt;黑魔法篇&lt;/h1&gt;

&lt;h2 id=&quot;function-extension&quot;&gt;Function extension&lt;/h2&gt;
&lt;p&gt;在很多地方，我们都可以看到&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;原生支持了类似&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Objective-c&lt;/code&gt;下的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Category&lt;/code&gt;特性，在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;下我们把这个特性叫做&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function extension&lt;/code&gt;。也就是说我们可以给任何已存在的类添加方法，包括在Java中的一些基本类型，而不是只能通过继承他们在子类中声明我们的方法。这个特性对我来说简直是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;killing feature&lt;/code&gt;一般的存在。这里我举一个具体的例子来说明&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function extension&lt;/code&gt;到底有多重要。&lt;/p&gt;

&lt;p&gt;在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Java&lt;/code&gt;的世界里，我们经常会写各种Util工具类，声明很多静态方法用于类型或者字符串转换。例如我们想对一个基本类型(比如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Float&lt;/code&gt;类型)转换为字符串，并进行一定的控制，比如下图中的这几种情况：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/demonnico/demonnico.github.com/raw/master/_images/53b6f3f65ed12f9705afb80b4157cfe3.png&quot; alt=&quot;Screen_Shot_2016_10_09_at_2_35_44_PM&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/demonnico/demonnico.github.com/raw/master/_images/98415eb7a6aaa2c90db8ad3e861d1768.png&quot; alt=&quot;Screen_Shot_2016_10_09_at_2_35_35_PM&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/demonnico/demonnico.github.com/raw/master/_images/ee34c5c28c2311a5b77db9725b79b6c8.png&quot; alt=&quot;Screen_Shot_2016_10_09_at_2_35_30_PM&quot; /&gt;&lt;/p&gt;

&lt;p&gt;在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;的世界里，使用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function extension&lt;/code&gt;来实现的话，我们可以这么做：&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Yuan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;formatter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DecimalFormat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.00&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;formatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;roundingMode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoundingMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;DOWN&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;￥&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;formatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这种链式写法在使用的时候非常方便，尤其是需要进行多次类型转换的时候，我们再也不用写类似&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AUtil.convert(BUtil.convert(value))&lt;/code&gt;一层层嵌套的代码了。相比之下链式调用也更符合OO语言习惯。&lt;/p&gt;

&lt;p&gt;或许有人会问了，那既然可以给已存在的类添加方法，那是否可以添加属性(成员)呢？答案是肯定的。但&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt; 官网的文档里并没有提及，我们在下面的篇幅里会详细介绍&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delegated properties&lt;/code&gt;这个黑魔法，进而引申出&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Property extension&lt;/code&gt;的一种实现。&lt;/p&gt;

&lt;h2 id=&quot;delegated-properties&quot;&gt;Delegated properties&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;!https://kotlinlang.org/docs/reference/delegated-properties.html&quot;&gt;Delegated properties(委托属性)&lt;/a&gt;在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;里是一种非常重要的实现机制，许多重要的特性可以基于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delegated properties&lt;/code&gt;来实现的。除了上文中提及的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Function Extension&lt;/code&gt;之外，像&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lazy&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lateinit&lt;/code&gt;特性也都可以视作基于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delegated properties&lt;/code&gt;的一种特性实现，并且我们还可以基于它来做一些属性观察(实时监听property的变化，类似&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Objective-C&lt;/code&gt;中的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KVO&lt;/code&gt;)的事情。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delegated properties&lt;/code&gt;使用起来非常简单，在申明变量的时候，跟上&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;by&lt;/code&gt;关键字，后面声明的就是我们的代理类。废话不多说，上码&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Example&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;member&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PropertyAttachedDelegation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyAttachedDelegation&lt;/code&gt;就是我们声明的委托类。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyAttachedDelegation&lt;/code&gt;的具体实现如下：&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PropertyAttachedDelegation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;KProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;):&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;KProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
	
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这里简单说明一下，在外部访问上文中&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Example&lt;/code&gt;对象的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;member&lt;/code&gt;属性时，会触发&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyAttachedDelegation &lt;/code&gt;的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getValue&lt;/code&gt;方法，相应地如果在对&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;member&lt;/code&gt;赋值时，会触发&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setValue&lt;/code&gt;方法。其中&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;thisRef&lt;/code&gt;代表的是被访问对象的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this&lt;/code&gt;引用，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;property&lt;/code&gt;参数是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KProperty&lt;/code&gt;类型，会体现当前&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyAttachedDelegation&lt;/code&gt;所修饰&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;member&lt;/code&gt;成员对象的一些运行时特性(类似Java中的反射机制)，例如成员变量名、类型等。最后的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;value&lt;/code&gt;则是通过set方法需要传入的值。&lt;/p&gt;

&lt;p&gt;那我们在实际开发过程中&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delegated properties&lt;/code&gt;有什么用处呢？&lt;/p&gt;

&lt;h2 id=&quot;property-extension&quot;&gt;Property extension&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;官网中并没有提到&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Property extension&lt;/code&gt;，这只是我基于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delegated properties&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Delegated properties&lt;/code&gt;特性的一个延伸。简单说，我们可以在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;里轻松实现给已有的类添加新的成员变量这个特性(在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Objective-C&lt;/code&gt;里我们可以基于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Category&lt;/code&gt;和运行时库的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objc_associate&lt;/code&gt;特性实现)。Takling is cheap, show me the code，上码：&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;data class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;age&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;gender&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;我们新建了一个叫做&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt;的&lt;a href=&quot;!https://kotlinlang.org/docs/reference/data-classes.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data class&lt;/code&gt;&lt;/a&gt;，现在只有&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;age&lt;/code&gt;、&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gender&lt;/code&gt;三个成员属性。如果我想在不修改&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt;类的情况下，添加一个叫做&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt;的成员，可以这么做：&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PropertyAttachedDelegation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;接下去我们对上文中提到的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyAttachedDelegation&lt;/code&gt;，进行进一步完善：&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PropertyAttachedDelegation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;{&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;//variablesMap是一个字典类型，类似HashMap&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;KProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;):&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variablesMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;T&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;  &lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;KProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Ref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variablesMap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;我们将PropertyAttachedDelegation声明为一个泛型类，这样保证了&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getValue&lt;/code&gt;方法的返回值与委托类修饰的变量类型保持一致。在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setValue&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getValue&lt;/code&gt;里通过&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;variablesMap&lt;/code&gt;对变量进行动态读取与存储，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;property&lt;/code&gt;保证读取与存储键值的一致性。说到这里，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;variablesMap &lt;/code&gt;又是从哪儿冒出来的呢？接着看下面的代码：&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variablesMap&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;lazy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kd&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;mutableMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MutableMap&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mutableMapOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;mutableMap&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//在Lazy表达式里，会将最后一个表达式的值隐式地作为返回值，不用显式声明retrun&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;里，所有类型都集成自&lt;a href=&quot;!https://kotlinlang.org/docs/reference/classes.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Any&lt;/code&gt;&lt;/a&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Any&lt;/code&gt;不是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.Object&lt;/code&gt;，当&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;里引入&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Java&lt;/code&gt;的类型时，所有的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;java.lang.Object&lt;/code&gt;类型都会&lt;a href=&quot;!https://kotlinlang.org/docs/reference/java-interop.html#object-methods&quot;&gt;动态地转换为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Any&lt;/code&gt;&lt;/a&gt;)，我们给&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Any&lt;/code&gt;动态声明一个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;variablesMap&lt;/code&gt;的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lazy&lt;/code&gt;属性，这样能保证&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;variablesMap&lt;/code&gt;在所有类型里都能被访问到，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt;保证了数据安全，无法被外部成员访问或者修改。因为是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lazy&lt;/code&gt;的，因此&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;variablesMap&lt;/code&gt;的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MutableMap&lt;/code&gt;仅在第一次被访问时才创建，避免了内存上的开销。做完这些事情，我们之后就可以快速地给任何对象添加任何类型的成员属性(property)了。比如我还想给上文中的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt;类型添加一个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tel&lt;/code&gt;字段，可以这样：&lt;/p&gt;

&lt;div class=&quot;language-kotlin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;py&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PropertyAttachedDelegation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;是不是很轻松？一劳永逸。自我感觉比&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Objective-C&lt;/code&gt;下的做法还优雅不少。&lt;/p&gt;

&lt;h1 id=&quot;总结&quot;&gt;总结&lt;/h1&gt;
&lt;p&gt;除了上文中提到的一些实战技巧，附件有我之前在线下分享时做的一个 &lt;a href=&quot;https://www.icloud.com/keynote/000SDjKQAvs2PkV0W03CDPk5w#Programming_Android_In_Kotlin&quot;&gt;Keynote&lt;/a&gt;，有兴趣的同学也可以下载下来看看，内容比这篇短文也要丰富些。总的来说&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;非常容易上手，对有&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;swift&lt;/code&gt;经验的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iOS&lt;/code&gt;开发者来说尤其友好。如果你有过一些&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Android&lt;/code&gt;开发经验或者说你正想学习&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Android&lt;/code&gt;开发又不想写&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Java&lt;/code&gt;的话，在我看来&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kotlin&lt;/code&gt;是一个非常好的选择。&lt;/p&gt;

&lt;p&gt;参考文章：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://kotlinlang.org/docs/reference/&quot;&gt;Kotlin Reference&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>你的Pod出现内存泄露了吗</title>
   <link href="http://blog.inico.me/2014/09/09/GPUImage-Leak-Cocoapods"/>
   <updated>2014-09-09T11:17:00+00:00</updated>
   <id>http://blog.inico.me/2014/09/09/GPUImage Leak Cocoapods</id>
   <content type="html">&lt;hr /&gt;
&lt;p&gt;GPUImage的作者BardLarson已经merge了我的&lt;a href=&quot;https://github.com/BradLarson/GPUImage/pull/1751&quot;&gt;RP&lt;/a&gt;，
该问题已解决。
不过既然都到这里了，我还是建议看完这篇文章，或许对你有帮助:P
***&lt;/p&gt;

&lt;p&gt;事情的起因是产品出了一个需求，要对Camera做实时模糊的效果。&lt;/p&gt;

&lt;p&gt;首先我想到的是用GPUImage来做，但是在使用GPUImage滤镜的时候发现每次都会出现&lt;a href=&quot;https://github.com/demon1105/GPUImageLeakDemo&quot;&gt;内存泄露&lt;/a&gt;，而且几乎所有滤镜都会有&lt;a href=&quot;https://github.com/BradLarson/GPUImage/issues/1681&quot;&gt;泄漏&lt;/a&gt;。后来想到了CoreImage内置了模糊的滤镜，而且CoreImage也支持硬件加速，于是放弃了GPUImage的方案，用CoreImage取而代之（iOS8已经支持&lt;a href=&quot;https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html&quot;&gt;自定义Kernel&lt;/a&gt;了，感兴趣的可以移步&lt;a href=&quot;http://holko.pl/2014/07/21/motion-blur/&quot;&gt;这里&lt;/a&gt;）。&lt;/p&gt;

&lt;p&gt;就在前几天在github上看到有朋友已经找到了上文中我提到的leak原因，并且提到了解决方案（不想看一大堆废话的可以直接看&lt;a href=&quot;https://github.com/BradLarson/GPUImage/issues/1748&quot;&gt;这里&lt;/a&gt;）。不敢私藏，写出来和大家一起分享。&lt;/p&gt;

&lt;p&gt;我们知道GCD中的对象在6.0之前是&lt;a href=&quot;http://stackoverflow.com/questions/12730202/do-you-need-to-release-gcd-queues-under-arc-in-ios-6-0&quot;&gt;不参与ARC&lt;/a&gt;的，而GPUImage目前支持最低的iOS版本是4.3，并且用到了ARC，因此Brad Larson在GPUImage里，用了一些条件编译来实现在iOS6.0之前GCG对象的手动释放。&lt;/p&gt;

&lt;p&gt;GPUImage中的条件语句如下：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dealloc&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;destroyDataFBO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#if ( (__IPHONE_OS_VERSION_MIN_REQUIRED &amp;lt; __IPHONE_6_0) || (!defined(__IPHONE_6_0)) )
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;movieWritingQueue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dispatch_release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;movieWritingQueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;audioQueue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dispatch_release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;audioQueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;videoQueue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dispatch_release&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;videoQueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;这里判断了当前系统支持的最小版本是否小于6.0，如果你在管理第三方库的时候没有用到Cocoapods，那应该说大多数情况下这么判断是没有问题的。但是如果用到了Cocoapods，细心的你会发现在GPUImage的pod里，compile sources的flag中多了一项&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOS_OBJECT_USE_OBJC=0&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demon1105/ImagesLib/master/GPUImage_DOS.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;查了一下关于&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOS_OBJECT_USE_OBJC&lt;/code&gt;的解释：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demon1105/ImagesLib/master/GPUImage_OS_define.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;我们发现恰恰是因为这一行定义，禁止了当前文件中的GCD对象参与ARC。至此，泄露的原因已经找到。事实上较好的做法是通过检查&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OS_OBJECT_USE_OBJC&lt;/code&gt;，因为在上述这种特定的条件下版本检测并不是完全通用。&lt;/p&gt;

&lt;p&gt;但问题是我们还得用Cocoapods来管理所有第三方库啊！或许你可以这样：&lt;/p&gt;

&lt;p&gt;1、设置pod时将将GPUImage的git地址改为我的&lt;a href=&quot;https://github.com/demon1105/GPUImage&quot;&gt;分支&lt;/a&gt;，这里我将用到的条件语句改为了推荐的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OS_OBJECT_USE_OBJC&lt;/code&gt;，&lt;a href=&quot;https://github.com/CocoaPods/CocoaPods/issues/1001&quot;&gt;检查特性而不是检查版本&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;2、偷懒的办法，fork GPUImage之后将.podspec文件中&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;deployment_target&lt;/code&gt;设置为6.0或以上，更新一下pod。&lt;/p&gt;

&lt;p&gt;因此，如果你的项目使用Cocoapods来管理第三方库，那就有必要稍微花点时间检查一下，确保没有出现因上述问题而造成的内存泄露。&lt;/p&gt;

&lt;p&gt;Over.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>用Swift实现Pinterest中的转场效果</title>
   <link href="http://blog.inico.me/2014/07/04/Swift-Pinterest-Transition-iOS7"/>
   <updated>2014-07-04T23:26:00+00:00</updated>
   <id>http://blog.inico.me/2014/07/04/Swift Pinterest Transition iOS7</id>
   <content type="html">&lt;p&gt;最近Swift风头正兴，让我有种不写几行Swift代码都不好意思说自己是做iOS开发的不祥预感。&lt;/p&gt;

&lt;p&gt;在&lt;a href=&quot;http://stackoverflow.com/questions/22900499/how-to-transition-from-uicollectionview-to-uiviewcontroller-like-pinterest-evern/24399337#24399337&quot;&gt;StackOverFlow&lt;/a&gt;上有人问Pinterest中转场的效果是如何实现的，在Pinterest的&lt;a href=&quot;http://engineering.pinterest.com/post/67769846580/behind-the-pins-building-pinterest-3-0-for-ios&quot;&gt;Blog&lt;/a&gt;上工程师大致对Pinterest的结构作了大致的介绍（这里再次对他们的开放态度再次钦佩），但是没有涉及到具体动画部分的实现。&lt;/p&gt;

&lt;p&gt;所以自己抽空用Swift重新实现了一遍这个转场的效果。在具体的项目应用中可能会比这个Demo复杂一些，但是动画的效果部分应该差不了多少，&lt;a href=&quot;https://github.com/demon1105/PinterestSwift&quot;&gt;上码&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://camo.githubusercontent.com/fdae059a7511ddab4e3dfdf5337c1ab85f9e60e9/687474703a2f2f692e737461636b2e696d6775722e636f6d2f30666e43642e676966&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Over.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>AVCaptureVideoPreviewLayer自定义相机</title>
   <link href="http://blog.inico.me/2014/06/27/camera-AVCaptureVideoPreviewLayer"/>
   <updated>2014-06-27T22:55:00+00:00</updated>
   <id>http://blog.inico.me/2014/06/27/camera AVCaptureVideoPreviewLayer</id>
   <content type="html">&lt;p&gt;之前在做自定义相机的时候，首先会想到用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIImagePickerViewController&lt;/code&gt;构建一个对象，直接设置&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sourceType&lt;/code&gt;为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIImagePickerControllerSourceTypeCamera&lt;/code&gt;就可以了。这样的做法简单暴力，而且界面和系统自带的Camera风格一致，比较省功夫。写了个简单的&lt;a href=&quot;https://github.com/demon1105/UIImagePickerDemo&quot;&gt;Demo&lt;/a&gt;，但这样做会有一个问题，在保存照片的时候会出现一个内存使用的小高峰。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demon1105/ImagesLib/master/uiimagepicker_memory.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;于是自己花了点时间用&lt;a href=&quot;https://github.com/demon1105/AVCapturePreviewLayerCamera&quot;&gt;AVCaptureVideoPreviewLayer&lt;/a&gt;重新实现了相机的功能，如果对定制要求比较高的话这样做更为适合，而且在保存的时候也不会出现像使用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UIImagePickerViewController&lt;/code&gt;时出现的内存问题。但有一些需要注意的是，存储时需要自己根据当前屏幕的朝向自行设置metadata的orientation信息，否则会出现打开后照片朝向不对的问题。但如果用户在Control Center把屏幕旋转给关了，我们无法在UIViewController的回调中得到当前屏幕的旋转信息怎么办？这里我们可以用CMMotionManager的加速度器传感器来做判断。&lt;/p&gt;

&lt;p&gt;Over.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>使用cocoapods创建多个类似工程的尝试</title>
   <link href="http://blog.inico.me/2014/05/07/iOS7.1-%E6%9E%B6%E6%9E%84-cocoapods-multipleTarget"/>
   <updated>2014-05-07T19:55:00+00:00</updated>
   <id>http://blog.inico.me/2014/05/07/iOS7.1 架构 cocoapods multipleTarget</id>
   <content type="html">&lt;p&gt;因为业务的需要，最近做了一批类似&lt;a href=&quot;https://itunes.apple.com/cn/app/wu-liao-tu-da-fa-wu-liao-shi/id687237182&quot;&gt;无聊图&lt;/a&gt;的App，应用本身没有复杂的逻辑，所有类“无聊图”的应用（以下称为S应用（similar App））都针对特定的用户群，设计了不同界面风格的，比如适合宅男的女神应用，适合吃货的美食应用等等诸如此类，大概一共七八个。&lt;/p&gt;

&lt;p&gt;首先我想到的办法是创建多个不同的target(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;多target&lt;/code&gt;)，分别在target里设置应用的特定资源（图片、类文件等等）。当然，首先我们要把公用的模块和资源抽取出来，以便在多个target之间共享。其余各target之间互斥的内容我们可以设置一个Config（配置中心）来做。假设我们有A、B、C三个应用，那么我们就要在Config中对应A、B、C填入不同的信息。这里可以是我们App的颜色主题，也可以是应用中所包含第三方平台（微博，微信等）分别分发给A、B、C的appKey信息。所以不拘一格，配置中心可以是一个简单的头文件，也可以是.plist文件（出于安全考虑，不要把一些关键的信息写到plist中。因为一般来说.plist文件会被Copy到&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bundle Resources&lt;/code&gt;中，所以信息会直接暴露在X.app目录下）。&lt;/p&gt;

&lt;p&gt;上面这个思路我在之前的公司做一款多语言包的游戏的时候用过，因为游戏中会涉及不同的资源包（主要是图片），创建多个target并且配合宏来做的话还算方便。这个思路具体的实现过程可以参照唐巧的&lt;a href=&quot;http://blog.devtang.com/blog/2013/10/17/the-tech-detail-of-ape-client-1/&quot;&gt;这篇文章&lt;/a&gt;，写得很详细。&lt;/p&gt;

&lt;p&gt;但是当我准备创建第四个target的时候就觉得有些烦躁了。因为在创建的时候很多过程都需要用鼠标点来点去。比如在copy一个target的时候你需要反选不需要出现在这个target中的资源文件，你需要用黑色的小箭头（鼠标指针）拖动新的图片到工程里，然后在松开的时候选择正确的target。如果手抖选错了那就得重新一张张图片去和target建立reference。做完这些工作之后我们还需要去scheme里修改target名称，否则默认的名称会以&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;source Target-&amp;gt;source Target copy&lt;/code&gt;的样式来呈现，第n个就是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;source Target-&amp;gt;source Target copy copy&lt;/code&gt;。这样的名字在项目里当然是不允许的。总得来说，还是觉得这个&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;多targets&lt;/code&gt;的解决方案里重复的劳动太多，难道办法解决这个问题了吗？当然有。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;cocoapods.org&quot;&gt;cocoapods&lt;/a&gt;对大家来说应该不算陌生了，于是我想到了用pod来替换target，每次切换target的行为转换为替换不同的pod。这样我们创建新项目的时候就可以不用鼠标来回点，取而代之的将是建立新的pod，替换pod中不同的资源后放在各个独立的git repo下（如果你喜欢用鼠标操作，亦或者觉得pod每次都要去update很麻烦。那很遗憾，这个办法可能不适合你）。这个方案我暂且称为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;多pod&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;接下来我将详细介绍这个方法。&lt;/p&gt;

&lt;p&gt;首先我们来看一下这个私有的Pod里包含了哪些内容：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demon1105/ImagesLib/master/resources.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;·图片资源文件（Icon、启动图等等）
·plist配置文件（可以是用来填写配置信息的文件，也可以是Info.plist等）
·头文件和一些.m实现文件（按照业务来，如果没有必要也可以不包含）
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里我把整个项目工程成为X，因为我之前已经将X中公用的模块理好了，所以创建新的工程的话就剩下如下这些操作：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1、添加A的启动图和Icon
2、添加预编译宏，以便程序在运行时知道当前到底是哪个App，从而实现一些差异化的代码。
3、一些程序中特有独立界面模块，逻辑的处理
4、替换Info.plist（填写Bundle display name，版本信息，第三方平台分发的一些需要填入到URL Types中的URL Scheme信息）
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里先分享我的podspec信息，看完后大家可能就已经明白一大半了。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;spec.source_files = 'classes/*.{h,m}'
spec.resource = 'resource/*'
  	spec.xcconfig = {&quot;GCC_PREPROCESSOR_DEFINITIONS&quot; =&amp;gt; '$(inherited) APP_A'}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;启动图的命名为&lt;a href=&quot;https://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/App-RelatedResources/App-RelatedResources.html&quot;&gt;Default.png、Default@2x.png、Default-568h@2x.png&lt;/a&gt;，icon的命名规范&lt;a href=&quot;https://developer.apple.com/LIBRARY/IOS/qa/qa1686/_index.html&quot;&gt;参照这里&lt;/a&gt;和&lt;a href=&quot;http://stackoverflow.com/questions/18663013/icon-file-names-ios-7&quot;&gt;这里&lt;/a&gt;，这些文件全都可以放在resource的。这样的话我们就无须在project里设置项目对启动图和icon的关联了。只要你的Bundle下存在这些图片，App在安装后自动选择最适合的icon，启动时会自动选取适合的启动图。关于在cocoapods里添加预编译参数可以&lt;a href=&quot;https://github.com/CocoaPods/Specs/issues/103&quot;&gt;参考这个issue&lt;/a&gt;。 这样的话，上面提到的1、2疑问就解决了。如果你的程序里有特殊的逻辑需要处理，那么也可以创建需要的类文件。然后在项目X中根据sepc.xcconfig中的预编译参数APP_A来判断：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#ifdef APP_A
//这里是你的一些特定的逻辑，爱干嘛干嘛吧
#endif 所以问题3也就迎刃而解了。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;因为我们已经把Info.plist也放在了Pod中（如果你切换了私有Pod的git repo指向后进行update，就相当于我们换了一个target），所以只要在X的工程设置里指定一次&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;路径就可以了。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demon1105/ImagesLib/master/plist-setting.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;咯里啰嗦说了一大堆，自己实现的过程中为了偷懒写了一个自动创建App中需要&lt;a href=&quot;https://gist.github.com/demon1105/8b3778a092150b30c3fe&quot;&gt;各种尺寸icon的小脚本&lt;/a&gt; ，还写了一个&lt;a href=&quot;https://github.com/demon1105/common-pod&quot;&gt;模板CommonPod&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;从现在开始，如果产品经理说需要新开发一个App，开发要做的就是clone CommonPod为一个新的Pod，替换资源，然后push到新的remote repo之后将更改项目的Podfile，pod update一次。是不是轻松些了呢？&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demon1105/ImagesLib/master/pod-setting.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;如果还不明白的的话就看这个&lt;a href=&quot;https://github.com/demon1105/demoProject&quot;&gt;Demo&lt;/a&gt;吧。&lt;/p&gt;

&lt;p&gt;对比一下以上的两个方案&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;·在项目配置的过程中，多target的方案需要做一些鼠标选择的操作。多pod方案只需要替换pod中的资源（命名都是一致的）。	
·在配置结束后的调试阶段，多target方案选择不同的target之后run即可，多pod方案则需要更改podfile后update（每次pod update觉得慢的同学可以试试--no-repo-update参数）。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;del&gt;最后补充一个多pod方案不足的地方，因为切换pod之后重新run相当于只是修改了&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info-common.plist&lt;/code&gt;的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bundle identifier&lt;/code&gt;，在模拟器上调试的时候会出现Xcode无法直接进入调试模式的问题。状况如下：&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/demon1105/ImagesLib/master/bug-xcode.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;del&gt;同样的情况会发生在新建Project运行之后，更改&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bundle identifier&lt;/code&gt;，然后再run一次。解决这个bug的方法是在下一次run之前先退出模拟器就可以了。但是如果在真机上进行调试，everything gonna be ok。&lt;/del&gt;
####（当当当！该问题在Xcode6.0上面已经完美解决）&lt;/p&gt;

&lt;p&gt;总结一下，多target方案麻烦在项目的设置上，&lt;del&gt;多pod方案麻烦在模拟器的调试阶段上（上面提到的bug），其实这两个办法都有些美中不足。&lt;/del&gt;写这篇文章的目的也并不是比个孰优孰劣，只是提供了一个新的思路去完成开篇时提到的业务需求。&lt;/p&gt;

&lt;p&gt;&lt;del&gt;PS：如果在多pod方案中的bug有可以解决的办法，请告诉我。谢谢&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;Over&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>如何将新版本的备份资料恢复至旧的iOS系统上</title>
   <link href="http://blog.inico.me/2014/02/20/iOS7.1-iOS7.0.4-backup-restore"/>
   <updated>2014-02-20T22:00:00+00:00</updated>
   <id>http://blog.inico.me/2014/02/20/iOS7.1 iOS7.0.4 backup restore</id>
   <content type="html">&lt;p&gt;今天终于入了&lt;a href=&quot;revealapp.com&quot;&gt;Reveal&lt;/a&gt;（公司给报销），于是想着把自己手机给越狱了，&lt;a href=&quot;http://blog.csdn.net/yiyaaixuexi/article/details/18220875&quot;&gt;reveal一下别的app玩玩&lt;/a&gt;。因为目前&lt;a href=&quot;http://evasi0n.com/&quot;&gt;jailbreak&lt;/a&gt;暂时只支持iOS7.0.5及以下的版本，而自己手机之前升到了iOS7.1Beta5，所以又要把系统给降下来。&lt;/p&gt;

&lt;p&gt;在restore系统之前用itunes backup了一下，一些就那么自然地开始了。等最后准备恢复刚才的backup的时候发现，itunes提示手机系统太久了（因为Backup是在iOS7.1beta5上建立的），心里真是有一万只草泥马在奔腾。&lt;/p&gt;

&lt;p&gt;当然办法总是有的，首先冷静下来，找到ituens在本地的backup目录&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/Library/Application\ Support/MobileSync/Backup/&lt;/code&gt;，然后打开对应的备份目录文件夹，按类别进行排序之后发现，有几个plist文件值得研究一下。大致浏览了一遍，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Manifest.plist&lt;/code&gt;主要保存了已经安装在iPhone上的app的一些bundle信息，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;State.plist &lt;/code&gt;包含了一些上次备份的状态信息。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;文件打开后豁然开朗，有几个Key让我激动了一下。一个是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Build Version&lt;/code&gt;，还有一个是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Product Version&lt;/code&gt;，这两者目前保存的都是7.1Beta5的版本信息，我将&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Build Version&lt;/code&gt;改为11B554a（7.0.4的Build Version，google或者找个7.0.4手机看一下都可以），&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Product Version&lt;/code&gt;改为当前手机的系统版本（7.0.4）。&lt;/p&gt;

&lt;p&gt;最后退出重启一下iTunes，找到先前无法restore的backup，再试一次~搞定。&lt;/p&gt;

&lt;p&gt;PS:此方法亲测在iOS7.0.4-&amp;gt;iOS7.1上有效，不保证iOS6的备份也可以。尝试之前请先另外备份&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Info.plist&lt;/code&gt;文件&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>iOS7下自定义barButtonItem后的奇怪问题</title>
   <link href="http://blog.inico.me/2013/12/26/iOS7,barButtonItem,"/>
   <updated>2013-12-26T22:55:00+00:00</updated>
   <id>http://blog.inico.me/2013/12/26/iOS7,barButtonItem,</id>
   <content type="html">&lt;p&gt;前几天在开发的时候碰到个奇怪的问题，将initWithCustomView出来的barButtonItem对象设置到navigationBar上之后，iOS7的设备下会出现interactivePopGestureRecognizer手势pop失效的问题。网上有解决方案是设置完navigationBar的buttonItem之后，重新将navigationController中的interactivePopGestureRecognizer设置为nil，这样虽然解决了手势的问题，但是在某些操作的情况下会出现新的问题。&lt;/p&gt;

&lt;p&gt;假设navigationController在push一个viewController的时候，迅速地通过手势进行pop操作，有时会出现navigationBar的titleView和对应的内容视图不一致的情况，有时界面会出现假死的情况（这种情况下home退出，再返回app，有一定的概率能回到正常状态），就好像navigationController中viewControllers的栈关系和导航里的内容错乱了，控制台中也会输出如下错误&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nested push animation can result in corrupted navigation bar&lt;/code&gt;，我随机挑选了手机中为iOS7优化过的app，其中Pinterest 3.3.1和啪啪 3.1.2都有这个类似的问题。和群里的朋友们讨论了一下，找到一个解决方案：设置interactivePopGestureRecognizer的delegate后，实现如下方法&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *）
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在 pushViewController 的时候适当设置标记禁用手势，0.5s 后重置，然后在 gestureRecognizerShouldBegin: 里修改标记。这样做的思路就是在push的时候禁用手势，等动画结束后再重新开启。&lt;/p&gt;

&lt;p&gt;但是一开始自己在用这个方法的时候发现并不是所有情况都能解决，后来发现原来是因为当初图省事，在开发的时候自己写了个BaseViewController的基类，然后override了ViewWillAppear和ViewWillDisappear，因为产品那边经常要统计进入某个界面的次数。但是由于部分的viewController继承BaseViewController:UIViewController的时候，在BaseViewController的viewDidLoad中错误地设置了navigationController.interactivePopGestureRecognizer的delegate，所以造成了刚才提到的情况。这里推荐使用MethodSwizzle替代继承的方案，不然下次不知道什么时候’基类‘又变成‘鸡肋’了···&lt;/p&gt;

&lt;p&gt;到此为止，这个奇怪的问题算是解决了。最后想说的是，如果可能的话，在iOS7下设置barButtonItem尽量不要用initWithCustomView方法，it makes me sick…&lt;/p&gt;

&lt;p&gt;PS：附上一个UIView的&lt;a href=&quot;https://github.com/demon1105/UIView-Utils&quot;&gt;category库&lt;/a&gt;，如果你是在代码里布局而不是通过IB的的话，应该用得到:D&lt;/p&gt;

&lt;p&gt;Over.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;附上一篇&lt;a href=&quot;http://blog.sina.com.cn/yzykhq&quot;&gt;@雨lei不是人&lt;/a&gt; 的&lt;a href=&quot;http://keighl.com/post/ios7-interactive-pop-gesture-custom-back-button/&quot;&gt;推荐方案👍&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>类Path中视差效果tableHeaderView的一种实现</title>
   <link href="http://blog.inico.me/2013/10/22/parallax"/>
   <updated>2013-10-22T22:55:00+00:00</updated>
   <id>http://blog.inico.me/2013/10/22/parallax</id>
   <content type="html">&lt;p&gt;接上篇文章中提到的类似知乎日报（类似Path2.0中的个人页面）中带前后视差效果的tableView如何实现，前段时间换了种实现方式，用起来也简单多了。具体实现的话时涉及到的技术点也无外乎Category、KVO这些，几句话就写完了。废话不多说，直接上&lt;a href=&quot;https://github.com/demon1105/NTParallaxView&quot;&gt;代码&lt;/a&gt;吧。:D&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.github.com/demon1105/ImagesLib/master/demo_parallaxview.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>最近的一些整理</title>
   <link href="http://blog.inico.me/2013/07/07/recently_works"/>
   <updated>2013-07-07T12:55:00+00:00</updated>
   <id>http://blog.inico.me/2013/07/07/recently_works</id>
   <content type="html">&lt;p&gt;这段时间公司的事情很多，所以没有及时更新。&lt;/p&gt;

&lt;p&gt;周五快下班的时候有同事问起类似知乎日报（类似Path2.0中的个人页面）中带前后视差效果的tableView如何实现，昨天花了点时间写了个&lt;a href=&quot;https://github.com/demon1105/NTParallaxScrollView&quot;&gt;Demo&lt;/a&gt;，这里给大家奉上。细心的朋友应该可以看得出来，知乎日报的实现方式和我写的其实略有不同。顶部的导航部分他们应该是添加了手势去做，所以拖动的时候没有类似ScrollView的分页效果。这里我参照了国外一个朋友实现的思路简单封装了一下，所以提供的只是一种实现的思路，如果有更好的方法也希望大家能够告诉我。(10-22日&lt;a href=&quot;https://github.com/demon1105/NTParallaxView&quot;&gt;更新&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;还有一个想和大家分享的和XCode5有关，之前在@onevcat的blog上看到一篇介绍XCode5特点的文章（不过因为NDA的关系，目前这几篇文章都暂时看不到了，不过可以借助google大神），其中有一点我这里想提的是，类似如下的注释：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * Setup a recorder for a specified file path. After setting it, you can use the other control method to control the shared recorder.
 *
 * @param talkingPath An NSString indicates in which path the recording should be created
 * @returns YES if recorder setup correctly, NO if there is an error
 */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;recordWithFilePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;talkingPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;在XCode5中将直接被检测到并集成进代码提示中，并且在Quick Help中也会有相关的提示。文章提到，可用的标识符除了上面的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@param&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@return&lt;/code&gt; 外，还有例如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@see&lt;/code&gt; ，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@discussion&lt;/code&gt;等，关于Javadoc的更多格式规则，可以参考 &lt;a href=&quot;http://en.wikipedia.org/wiki/Javadoc&quot;&gt;Wiki&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;但是真正的高潮还没到，类似如上的注释如果一个一个去敲，岂不是太反人类了？所以这里奉上一个自动在&lt;a href=&quot;http://blog.chukong-inc.com/index.php/2012/05/16/xcode4_fast_doxygen/&quot;&gt;XCode中添加注释的脚本还有设置方法&lt;/a&gt;，结合这个脚本，写注释应该会变成一件很爽的事情。所以也希望大家以后养成勤写注释，写好注释的好习惯:D&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;http://onevcat.com/&quot;&gt;@onevcat&lt;/a&gt; 最近刚完成了一个自动注释的&lt;a href=&quot;https://github.com/onevcat/VVDocumenter-Xcode&quot;&gt;插件&lt;/a&gt;，功能已经差不多了，可以关注一下。&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;还有如下的一些文章，感兴趣的朋友也可以学习一下&lt;/p&gt;

&lt;p&gt;破船翻译的iOS汇编教程
&lt;a href=&quot;http://beyondvincent.com/2013/06/19/ios%E6%B1%87%E7%BC%96%E6%95%99%E7%A8%8B%EF%BC%9Aarm/&quot;&gt;ARM–1&lt;/a&gt;
&lt;a href=&quot;http://beyondvincent.com/2013/06/20/ios%E6%B1%87%E7%BC%96%E6%95%99%E7%A8%8B%EF%BC%9Aarm2/&quot;&gt;ARM–2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;唐巧-&lt;a href=&quot;http://blog.devtang.com/blog/2013/06/23/alipay-plugin-mechanism/&quot;&gt;支付宝插件机制分析&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Allen-&lt;a href=&quot;http://imallen.com/blog/2013/06/26/inside-alipay-plugin.html&quot;&gt;浅析支付宝钱包插件&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Colorful XCode Console</title>
   <link href="http://blog.inico.me/2013/06/05/cocoalumberjack_xcodecolors"/>
   <updated>2013-06-05T22:22:00+00:00</updated>
   <id>http://blog.inico.me/2013/06/05/cocoalumberjack_xcodecolors</id>
   <content type="html">&lt;p&gt;前几天在&lt;a href=&quot;http://blog.devtang.com/&quot;&gt;唐巧&lt;/a&gt;的微信公共账号（iosDevTips）里，收到一条关于如何在开发的时候，在控制台中更友好地输出Log的消息。里面大致提到了三个方案&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;用Emoji放到每行行首，作为区分。（From &lt;a href=&quot;http://lextang.com/&quot;&gt;汤圣罡&lt;/a&gt; tang sheng gang，第三个字我去查了:D）&lt;/li&gt;
  &lt;li&gt;基于&lt;a href=&quot;https://github.com/robbiehanson/CocoaLumberjack&quot;&gt;CocoaLumberjack&lt;/a&gt;的开源方案&lt;/li&gt;
  &lt;li&gt;AppCode，有插件可以设置Log着色(From 黎伟)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;我只用过第二种，而且用起来也挺方便。关于什么是CocoaLumberjack，有什么优点，我这里就不再累述了，反正谁用谁知道，想了解的直接去Github上看吧。因为看到许多朋友说尝试后都失败了，这里说说我的设置步骤。&lt;/p&gt;

&lt;p&gt;首先我的项目(ProjectA)是用Cocoapods管理的（当然你可以直接把CocoaLumberjack所有的文件拖到自己的项目里，如果你不觉得这么做很麻烦的话），所以在podfile里面添加&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pod 'CocoaLumberjack'&lt;/code&gt;，然后pod update就可以了。&lt;/p&gt;

&lt;p&gt;因为CocoaLumberjack的Color Log是依赖&lt;a href=&quot;https://github.com/robbiehanson/XcodeColors&quot;&gt;XcodeColor&lt;/a&gt;插件的，因此我们也必需安装这个插件。装完后重新启动一下Xcode，然后先试试XcodeColors的Demo Project,确定插件已经成功安装。&lt;/p&gt;

&lt;p&gt;接下来在ProjectA里（可以是applicationDidFinishLaunchingWithOptions)设置一下日志的输出级别（可以按照级别输出，只输出警告，错误，或者全部），对lumberjack进行初始化，并且打开Color Log的开关&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ddLogLevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOG_LEVEL_VERBOSE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Standard lumberjack initialization&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DDLog&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addLogger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DDTTYLogger&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sharedInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]];&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// And we also enable colors&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DDTTYLogger&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sharedInstance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setColorsEnabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;YES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;这样的话你就可以用DDLogInfo,DDLogError等取代之前的NSLog了。默认的话DDLogError输出是红色的，DDLogWarn是黄色的（我喜欢这个颜色:D）。&lt;/p&gt;

&lt;p&gt;到目前为止，对于我来说至少是在模拟器上调试的时候输出的Log都带颜色了，但后来我发现在真机上调试的时候输出的还是黑色的Log。后来在Wiki的&lt;a href=&quot;https://github.com/robbiehanson/CocoaLumberjack/wiki/XcodeColors&quot;&gt;XcodeColors in iOS&lt;/a&gt;上发现了这么一条&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;You may occasionally notice that colors don't work when you're debugging your app in the simulator. And you may also notice that you colors never work when debugging on the actual device. How do I fix it so it works everywhere, all the time?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我运气可能算比较好，每次在模拟器上调试的时候都正常有颜色输出。按照提示我对Project的Scheme作了如下调整：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In Xcode bring up the Scheme Editor (Product -&amp;gt; Edit Scheme…)&lt;/li&gt;
  &lt;li&gt;Select “Run” (on the left), and then the “Arguments” tab&lt;/li&gt;
  &lt;li&gt;Add a new Environment Variable named “XcodeColors”, with a value of “YES”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;最后重新Cmd+R一次，搞定，我在Xcode4.4和Xcode4.6上都做过测试，都是可以的。所以在我这里目前不存在Xcode版本不一致而造成彩色日志输出失败的问题。如果有朋友按照如上的步骤设置还是不成功，欢迎在评论里留言提出疑问，一起讨论。&lt;/p&gt;

&lt;p&gt;最后附上真相&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.github.com/demon1105/ImagesLib/master/color_log.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;今天微博上有位叫&lt;a href=&quot;http://weibo.com/kaixinger&quot;&gt;开星儿&lt;/a&gt;的朋友提到了&lt;a href=&quot;http://bluedogtech.blogspot.com/2010/12/global-log-level-control-with.html&quot;&gt;这篇文章&lt;/a&gt;，感兴趣的朋友可以翻过去看一下，你应该不会后悔。&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;因为XCode5下对插件安装多了一层验证，因此升级XCode5之后造成插件失灵的话，请移步&lt;a href=&quot;https://github.com/demon1105/XcodeColors&quot;&gt;这里&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>从wordpress到jekyll</title>
   <link href="http://blog.inico.me/2013/05/19/wordpress_jekyll_exchange"/>
   <updated>2013-05-19T20:00:00+00:00</updated>
   <id>http://blog.inico.me/2013/05/19/wordpress_jekyll_exchange</id>
   <content type="html">&lt;p&gt;周末花了点时间把之前一些写的东西从wordpress换到了基于jekyll的github pages，因为没有数据库，界面也都是静态生成的，所以访问的速度很快。文章用markdown来写，这样的话每次要新增一篇文章只要新建一个.markdown文件后保存后提交，如果修改文章，在git下面也有更改的记录。还有关键的一点是这个空间是免费的，速度快，感觉很不错。下面简单说一下Mac下的一些安装和迁移步骤。&lt;/p&gt;

&lt;p&gt;首先通过wordpress自带的export工具，把之前所有的文章导出为xml。然后借助github上的&lt;a href=&quot;https://github.com/thomasf/exitwp&quot;&gt;exitwp&lt;/a&gt;工具将xml中文章导出为markdown的文件。注意一下，exitwp是用Python写的，而且需要html2text、PyYAML、Beautiful soup的支持，exitwp的wiki上也有写，不过我在安装的时候碰到个小问题，Beautiful soup虽然安装成功，但是运行exitwp的脚本时import Beautiful soup报错，因为最新版的Beautiful soup 4的import目录有所改变，不过刚看了下exitwp的作者已经修改好了。&lt;/p&gt;

&lt;p&gt;如果你想写好文章之后先在自己电脑上预览一下然后post，那么&lt;a href=&quot;http://jekyllrb.com/docs/installation/&quot;&gt;本地安装一下jekyll&lt;/a&gt;是必须的。然后基于&lt;a href=&quot;http://jekyllbootstrap.com/&quot;&gt;jekyllbootstrap&lt;/a&gt;进行安装。代码高亮的话我用&lt;a href=&quot;http://pygments.org/&quot;&gt;Pygments&lt;/a&gt;搞定。&lt;/p&gt;

&lt;p&gt;因为之前的评论也是用disqus，所以迁移过来非常方便。但是有一点要注意一下，默认在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;里的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;permalink&lt;/code&gt;是&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/:categories/:year/:month/:day/:title &lt;/code&gt;，但是我之前所有的post都是不带categories的，所以这里应该改为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/:year/:month/:day/:title &lt;/code&gt;，不然之前在其他地方引用到的地址都会变成死链接，当然也找不到disqus上对应的正确评论。然后把disqus上的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;short_name&lt;/code&gt;换一下就可以了。&lt;/p&gt;

&lt;p&gt;最后cd至你的jekyll站点目录下，启动一下&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll serve&lt;/code&gt;，默认在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;localhost:4000&lt;/code&gt;就可以访问到了，没问题的话&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push&lt;/code&gt;一下，第一次提交的话可能需要过一会儿，你就可以在你的github page上访问了。如果你已经有自己的域名了，只要在目录下添加一个CNAME文件，然后写上你自己的域名，在域名提供商那边修改解析规则，添加一条&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;207.97.227.245&lt;/code&gt;到A记录。&lt;/p&gt;

&lt;p&gt;最后需要补充一点，默认使用的markdown引擎应该是maruku，所以会碰到有时候markdown–&amp;gt;html的时候出错，类似&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REXML could not parse this XML/HTML:&lt;/code&gt;，这里可以修改_config.yml，我用了rdiscount，所以添加&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;markdown : rdiscount &lt;/code&gt;后重新启动服务，整个世界就清净了~~&lt;/p&gt;

&lt;p&gt;推荐一个免费的Markdown编辑神器&lt;a href=&quot;http://mouapp.com/&quot;&gt;Mou&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>iOS离屏绘制的性能和机制分析</title>
   <link href="http://blog.inico.me/2013/05/18/ios_offscreen_analysis"/>
   <updated>2013-05-18T14:17:56+00:00</updated>
   <id>http://blog.inico.me/2013/05/18/ios_offscreen_analysis</id>
   <content type="html">&lt;p&gt;接上一篇文章提到的，评论中有一个Apple UIKit teamer，叫Andy Matuschak的一些补充内容。&lt;/p&gt;

&lt;p&gt;—Begin—&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Hey, cool! I think it's great that you followed up with a post focusing on performance. Your advice as far as the button is good here, but I've got one small correction and some bonus explanation for interested readers.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;太牛逼了！我觉得你这篇注重性能表现的文章写得很好。到目前为止你的建议对button的分析来说很到位，但是对一些意犹未尽的读者来说我这里还有一些需要补充的部分。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;I'd like to clarify a few points about offscreen drawing as described in this post. While your list of cases which might elicit offscreen drawing is accurate, there are two grossly different mechanisms being triggered by elements of this list (each with different performance characteristics), and it's possible that a single view will require both. Those two mechanisms have very different performance considerations.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;关于在你文章中提到的离屏绘制，我这里还有几点需要补充。虽然在你文章中提到关于离屏绘制的例子很犀利，但是我想说在这些例子里涉及到两种截然不同的机制（每一种都有不同性能表现上的特点），并且有可能单个视图两者都涉及到了。在使用的时候也需要考虑到这两种机制不同的性能。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;In particular, a few (implementing drawRect and doing any CoreGraphics drawing, drawing with CoreText [which is just using CoreGraphics]) are indeed &quot;offscreen drawing,&quot; but they're not what we usually mean when we say that. They're very different from the rest of the list. When you implement drawRect or draw with CoreGraphics, you're using the CPU to draw, and that drawing will happen synchronously within your application. You're just calling some function which writes bits in a bitmap buffer, basically.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;一方面来说，一部分（通过drawRect并且使用任何CoreGraphics来实现的绘制，或使用CoreText[其实就是使用CoreGraphics]绘制）的确涉及到了“离屏绘制”，但是这有区别与我们通常说的那种离屏绘制。这一部分和以上例子中其他的都不一样。当你实现drawRect方法或者通过CoeGraphics绘制的时候，其实你是在使用CPU绘制。并且这个绘制的过程会在你的App内同步地进行。基本上你只是调用了一些向位图缓存内写入一些二进制信息的方法而已。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The other forms of offscreen drawing happen on your behalf in the render server (a separate process) and are performed via the GPU (not via the CPU, as suggested in the previous paragraph). When the OpenGL renderer goes to draw each layer, it may have to stop for some subhierarchies and composite them into a single buffer. You'd think the GPU would always be faster than the CPU at this sort of thing, but there are some tricky considerations here. It's expensive for the GPU to switch contexts from on-screen to off-screen drawing (it must flush its pipelines and barrier), so for simple drawing operations, the setup cost may be greater than the total cost of doing the drawing in CPU via e.g. CoreGraphics would have been. So if you're trying to deal with a complex hierarchy and are deciding whether it's better to use -[CALayer setShouldRasterize:] or to draw a hierarchy's contents via CG, the only way to know is to test and measure.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;而另外一种形式离屏绘制是发生在绘制服务（是独立的处理过程）并且同时通过GPU执行（这里就不是像前面提到的用CPU了）。当OpengGL的绘制程序在绘制每个layer的时候，有可能因为包含多子层级关系而必须停下来把他们合成到一个单独的缓存里。你可能认为GPU应该总是比CPU牛逼一点，但是在这里我们还是需要慎重的考虑一下。因为对GPU来说，从当前屏幕（on-screen）到离屏（off-screen）上下文环境的来回切换（这个过程必须flush管线和光栅，原文是it must flush its pipelines and barrier，这里不知道怎么翻译比较合适，回头补补openGL的东西），代价是非常大的。因此对一些简单的绘制过程来说，这个过程有可能用CoreGraphics，全部用CPU来完成反而会比GPU做得更好。所以如果你正在尝试处理一些复杂的层级，并且在犹豫到底用-[CALayer setShouldRasterize:] 还是通过CoreGraphics来绘制层级上的所有内容，唯一的方法就是测试并且进行权衡。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;You could certainly end up doing two off-screen passes if you draw via CG within your app and display that image in a layer which requires offscreen rendering. For instance, if you take a screenshot via -[CALayer renderInContext:] and then put that screenshot in a layer with a shadow.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果在你的App里通过CoreGraphics来绘制，并且在layer上通过离屏绘制的方式来呈现image，你就可以体会到两种不同的off-screen绘制过程。举个具体的例子来就是说，你通过[CALayer renderInContext:] 得到了一张截图之后再把它放到一个layer中，并且打开shadow属性。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Also: the considerations for shouldRasterize are very different from masking, shadows, edge antialiasing, and group opacity. If any of the latter are triggered, there's no caching, and offscreen drawing will happen on every frame; rasterization does indeed require an offscreen drawing pass, but so long as the rasterized layer's sublayers aren't changing, that rasterization will be cached and repeated on each frame. And of course, if you're using drawRect: or drawing yourself via CG, you're probably caching locally. More on this in &quot;Polishing Your Rotation Animations,&quot; WWDC 2012.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;还有需要注意的是，shouldRasterize和masking（遮罩）, shadows（阴影）, edge antialiasing,（抗锯齿），group opacity属性都不一样。如果后面这些提到的属性是开启的，就不会有缓存，并且离屏绘制将会在每一帧都发生；rasterization（光栅化）的确涉及到了离屏绘制，不过如果被光栅化之后的layer的sublayers如果没有发生改变，那么刚才说的光栅化后的内容将会被缓存起来并且在之后frame刷新过程中被复用。当然了，如果你正在使用drawRect或者用CoreGraphics绘制，你有可能正在使用本地的缓存机制。更多的内容可以参照WWDC2012的 Polishing Your Rotation Animations（不知道是不是&lt;a href=&quot;http://v.youku.com/v_show/id_XNTQxNjk4NTQw.html&quot;&gt;Polishing Your Interface Rotation Animations&lt;/a&gt;）的内容。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Speaking of caching: if you're doing a lot of this kind of drawing all over your application, you may need to implement cache-purging behavior for all these (probably large) images you're going to have sitting around on your application's heap. If you get a low memory warning, and some of these images are not actively being used, it may be best for you to get rid of those stretchable images you drew (and lazily regenerate them when needed). But that may end up just making things worse, so testing is required there too.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;说到缓存，如果你在App里面正在使用大量的绘制工作，你可能需要为你程序的堆内存中无所事事的images（有可能是大图）实现清空缓存的工作。如果你得到了内存警告，同时这些图片又不不在使用，你最好把之前绘制的时候需要的stretchable的图片全都释放（当需要的时候再通过lazy方式生成）。但是这也有可能会使情况变得更加糟糕，所以说到底，这个也需要经过测试。&lt;/p&gt;

&lt;p&gt;—Over—&lt;/p&gt;

&lt;p&gt;我怕翻译得不够到位，所以原文我也附上来了。&lt;/p&gt;

&lt;p&gt;如果觉得翻译得不好的希望在评论里指点一下，谢谢:D&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>iOS图形处理和性能</title>
   <link href="http://blog.inico.me/2013/05/18/designing-for-ios-graphics-performance"/>
   <updated>2013-05-18T00:15:43+00:00</updated>
   <id>http://blog.inico.me/2013/05/18/designing-for-ios-graphics-performance</id>
   <content type="html">&lt;p&gt;原文的题目是&lt;a href=&quot;http://robots.thoughtbot.com/post/36591648724/designing-for-ios-graphics-performance&quot;&gt;Designing for iOS: Graphics &amp;amp; Performance&lt;/a&gt;，晚上花了两个不到小时大致翻译了下。&lt;/p&gt;

&lt;p&gt;—Begin—&lt;/p&gt;

&lt;p&gt;在&lt;a href=&quot;http://robots.thoughtbot.com/post/33427366406/designing-for-ios-taming-uibutton&quot;&gt;之前的文章&lt;/a&gt;里，我们探讨了基于多种不同技术来实现自定义的UIButton，当然不同的技术所涉及到的代码复杂度和难度也不一样。但是我也有意提到了基于不同方法的实现所体现出的性能表现也不一一相同。&lt;/p&gt;

&lt;p&gt;【在屏幕背后的东西】&lt;/p&gt;

&lt;p&gt;为了了解性能是如何受到影响的，我们需要进一步地观察iOS里图形实现背后的一些内容。下面这张图呈现了不同的frameworks和libraries之间的一些联系：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://pic.yupoo.com/demon42111915/CRYk1ku8/medish.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;在最顶层的就是UIKit，一个在iOS中用来管理用户图形交互的Objc高级的框架，它由一系列的集合类构成，例如UIButton、UILabel，每一个都负责他们指定的UI Control角色。UIKit本身构建在一个叫Core Animation的框架之上，它因为被用于处理更为强大的平滑的转场效果而引入OS X Leopard和iOS而出名。&lt;/p&gt;

&lt;p&gt;再往下深入一点就是OpenGL ES了，一个用在移动设备上绘制2D和3D计算机图形的标准开源库，它广泛地被用在游戏的图形绘制上，同样在Core Animation和UIKit中发挥着强大的作用。&lt;/p&gt;

&lt;p&gt;最后一部分就是Core Graphics，曾经在Quartz（一个基于CPU的绘制引擎，在OS X系统上初次露脸）中被引入。这两个较为底层的框架都是用C语言编写的。&lt;/p&gt;

&lt;p&gt;上图中的最底下一行是硬件层，由GPU和CPU组成。&lt;/p&gt;

&lt;p&gt;我们经常说到的硬件加速其实是指OpenGL,Core Animation/UIKit基于GPU之上对计算机图形合成以及绘制的实现，直到目前为止，iOS上的硬件加速能力还是大大领先与android，后者由于依赖CPU的绘制，绝大多数的动画实现都会让人感觉明显的卡顿。&lt;/p&gt;

&lt;p&gt;而离屏绘制(Offscreen drawing)的话就是指GPU一边在当前屏幕上进行绘制，而另一边在屏幕还没有处理图像信息之前通过CPU来生成图像信息的处理过程。在iOS当中，离屏绘制在以下的情况下会自动触发：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;* Core Graphics(任何以CG开头的类)
* 在drawRect方法里，甚至是空方法实现
* 所有shouldRasterize属性是YES的CALayers对象	
* 所有用了masks(setMasksToBounds)和动态阴影的(setShadow*)的CALayers对象
* 所有文字的绘制，包括CoreText
* Group opacity(UIViewGroupOpacity)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;总地来说，当有涉及到动画的时候离屏绘制就会影响到性能，你可以通过Instruments进行真机调试，从而检测到底是哪部分UI正在进行离屏绘制：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;接入设备&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;在XCode的Developer Applications里打开Instruments（Command+Shift+i）   
  &lt;img src=&quot;http://pic.yupoo.com/demon42111915/CRYj9u3F/medish.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;选择iOS&amp;gt;Graphics&amp;gt;Core Animation template
  &lt;img src=&quot;http://pic.yupoo.com/demon42111915/CRYj8kna/medish.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;打开详情面板，选择适当的窗口模式  &lt;br /&gt;
  &lt;img src=&quot;http://pic.yupoo.com/demon42111915/CRYj7Ik3/medish.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;选择你的target设备&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;检查Color Offscreen-Rendered Yellow的debug选项&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;在你设备上所有的离屏绘制都会呈现出黄色的色调&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;http://pic.yupoo.com/demon42111915/CRYj7ix4/medish.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;现在让我们逐一检查上一篇文章里涉及的一些技术点的性能表现。&lt;/p&gt;

&lt;p&gt;【预资源加载绘制】&lt;/p&gt;

&lt;p&gt;使用UIImage来加载原先就在磁盘中的图片作为自定义UIButton的背景图片的话，完全依赖与GPU的绘制。而且如果用可resizable的图片，也可适当避免当背景大小动态变换的时候需要不同大小的图片，这样可以让我们App的bundle做得更小，而且在绘制像素的图的时候也重复地利用了硬件加速。&lt;/p&gt;

&lt;p&gt;【使用CALayer】&lt;/p&gt;

&lt;p&gt;因为基于CALayer实现的方法里我们使用到了遮罩去绘制圆角的效果，所以这里会涉及到离屏绘制。当我们使用Core Animation框架的时候，如果上面提到的用遮罩绘制圆角的属性是开启的话，我们也必须明确地禁止使用动画效果。作为底线，除非你非要进行一个动画转场效果，否则这种方法并不适用。&lt;/p&gt;

&lt;p&gt;【使用drawRect】&lt;/p&gt;

&lt;p&gt;drawRect方法依赖Core Graphics框架来进行自定义的绘制，但这种方法主要的缺点就是它处理touch事件的方式：每次按钮被点击后，都会用setNeddsDisplay进行强制重绘；而且不止一次，每次单点事件触发两次执行。这样的话从性能的角度来说，对CPU和内存来说都是欠佳的。特别是如果在我们的界面上有多个这样的UIButton实例。&lt;/p&gt;

&lt;p&gt;【技巧混合 hybrid approach】&lt;/p&gt;

&lt;p&gt;这样来说的话，是不是就意味着使用预资源加载进行绘制就是唯一可行的方案了呢？答案是否定的。如果你坚持需要用代码来灵活地进行绘制的话，还是有一些优化代码还有减少性能消耗方面的技巧的。有一种可行的方案就是创建stretchable的位图并在多个实例对象之间进行重用。&lt;/p&gt;

&lt;p&gt;我们按照在之前的教程的相同步骤创建一个新的UIButton的子类，然后如下定义一些静态变量&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;    
 &lt;span class=&quot;c1&quot;&gt;// In CBHybrid.m&lt;/span&gt;
 &lt;span class=&quot;cp&quot;&gt;#import &quot;CBHybrid.h&quot;
&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;@implementation&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CBHybrid&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Resizable background image for normal state static UIImage *gBackgroundImage;&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Resizable background image for highlighted state static UIImage *gBackgroundImageHighlighted;&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Background image border radius and height&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;接下来我们把CBBezie内drawRect里的代码换个地方，通过一系列的改变之后：我们可以创建一个resizable的Image用来取代之前固定尺寸的Image，然后我们可以持有该静态对象并便于重用&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;    &lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;drawBackgroundImageHighlighted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;highlighted&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Drawing code goes here&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;首先，我们需要知道我们resizable Image的宽，为了优化性能，我们应该在图片的中间保留一个像素的宽&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;高的话在这个case里就不是非常重要了，因为这个按钮的高度对渐变层来说已经足够可见，设置为37pt的话也是出于和其余几个按钮的高度相同的原因。&lt;/p&gt;

&lt;p&gt;搞定之后，我们需要一个bitmap context来进行绘制，搞起~&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;n&quot;&gt;UIGraphicsBeginImageContextWithOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CGSizeMake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CGContextRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UIGraphicsGetCurrentContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CGColorSpaceRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;colorSpace&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGColorSpaceCreateDeviceRGB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;UIGraphicsBeginImageContextWithOptions第二个参数为NO的话确保我们创建的Image context是透明的（带Alpha），最后的参数是scale factor(屏幕密度)，如果是0的话就是当前设备的默认scale factor。&lt;/p&gt;

&lt;p&gt;接下来的代码就和我们之前用Core Graphics来实现CBBezier的Demo里用到的非常相像了。我们用highlighted参数替换默认的self.highlighted属性，把用作更新界面的图像的信息值保存下来。&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Gradient Declarations&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// NSArray *gradientColors = ...&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Draw rounded rectangle bezier path&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;UIBezierPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;roundedRectanglePath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIBezierPath&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bezierPathWithRoundedRect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGRectMake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cornerRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Use the bezier as a clipping path&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;roundedRectanglePath&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addClip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Use one of the two gradients depending on the state of the button&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CGGradientRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;background&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;highlighted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;highlightedGradient&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gradient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Draw gradient within the path&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;CGContextDrawLinearGradient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGPointMake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;140&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGPointMake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;140&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Draw border&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [borderColor setStroke...&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Draw Inner Glow&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// UIBezierPath *innerGlowRect...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;我们唯一需要添加的步骤就是，用UIGraphicsEndImageContext来保存图像信息，并且放到UIImage对象中。&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;n&quot;&gt;UIImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;backgroundImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UIGraphicsGetImageFromCurrentImageContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    
&lt;span class=&quot;c1&quot;&gt;// Cleanup&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;UIGraphicsEndImageContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;现在我们已经完成了创建背景图片的方法，接下来我们必须实现一个通用的初始化方法用来实例化Images，并且把他们设置为CBHybird实例真正的背景。&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setupBackgrounds&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Generate background images if necessary&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gBackgroundImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gBackgroundImageHighlighted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;gBackgroundImage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;drawBackgroundImageHighlighted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resizableImageWithCapInsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIEdgeInsetsMake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resizingMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIImageResizingModeStretch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;gBackgroundImageHighlighted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;drawBackgroundImageHighlighted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;YES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resizableImageWithCapInsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIEdgeInsetsMake&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;borderRadius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resizingMode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIImageResizingModeStretch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Set background for the button instance&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setBackgroundImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gBackgroundImage&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;forState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIControlStateNormal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setBackgroundImage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gBackgroundImageHighlighted&lt;/span&gt; 					&lt;span class=&quot;nf&quot;&gt;forState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIControlStateHighlighted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;我们可以用custom的类型来实例化我们的CBHybird，当然也可以用initWithCoder，如果想用在代码里实现的话我们还可以用initWithFrame(···其实这里我是不想翻译的，原作者写得真是太详细了，第一次翻译技术文章，还是彻底点吧。。。)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;    
&lt;span class=&quot;k&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CBHybrid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;buttonWithType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIButtonType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;type&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buttonWithType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIButtonTypeCustom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;initWithCoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSCoder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;aDecoder&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;super&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initWithCoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aDecoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
       &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setupBackgrounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;为了确保我们新建的BHybird类能正常使用，在Interface Builder里我们赋值一个button，把实现类改成CBHybird后，把button的content内容改为_CGContext-generated image（_便于区分）。是驴是马，咱们cmd+R跑起来试试~&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://pic.yupoo.com/demon42111915/CRYj7cxT/medish.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;完整的子类实现代码在&lt;a href=&quot;https://github.com/demon1105/custom-UIButton/blob/master/Custom%20UIButtons/CBHybrid.m&quot;&gt;这里&lt;/a&gt;~~~&lt;/p&gt;

&lt;p&gt;【结束语】&lt;/p&gt;

&lt;p&gt;所有都搞定之后，我们发现用预资源加载绘制仍然比任何一种基于代码实现的方案表现得更为出色。然而，Core Graphicsis在效率和灵活性上更有优势。因此，基于两种技巧的混合方案在现在看来包含了以上两个的长处，而且在性能上也并没有明显的影响。&lt;/p&gt;

&lt;p&gt;—Over—&lt;/p&gt;

&lt;p&gt;第一次翻译，有些地方可能不是很到位，不足的地方请见谅:D&lt;/p&gt;

&lt;p&gt;原文的评论中有篇精彩的回复，作者也有提到，感兴趣的可以看看。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>iOS如何避免图像解压缩的时间开销（转）</title>
   <link href="http://blog.inico.me/2013/05/09/ios_uiimage_optimizer"/>
   <updated>2013-05-09T19:38:24+00:00</updated>
   <id>http://blog.inico.me/2013/05/09/ios_uiimage_optimizer</id>
   <content type="html">&lt;p&gt;这几天一直在折腾项目中UITableView的优化。&lt;/p&gt;

&lt;p&gt;因为cell中涉及到很多（而且很大）的图片，所以在快速滚动的时候，ImageView重新绘制新的图片造成了比较大的性能消耗。查了挺多的资料，看到一篇分析jpg,png（优化前后）在各个设备上测试分析，原文在这里（&lt;a href=&quot;http://www.cocoanetics.com/2011/10/avoiding-image-decompression-sickness/&quot;&gt;voiding Image Decompression Sickness&lt;/a&gt;），本来想自己翻译的，后来在LongTimeNoC看到已经翻译好的，就转过来了。&lt;/p&gt;

&lt;p&gt;———BEGIN———&lt;/p&gt;

&lt;p&gt;当开始&lt;a href=&quot;http://www.cocoanetics.com/2010/10/icatalog-framework-brings-digital-catalogs-to-life-on-ipad/&quot;&gt;iCatalog.framework&lt;/a&gt;的工作时，我发现使用大尺寸图片会引起一些恼人的问题，“大”意味着这个图片有足够大的分辨率（1024×768）来覆盖iPad的整个屏幕，或者覆盖未来Retina Display iPad（如果有的话）的双倍分辨率（2048×1536）屏幕。&lt;/p&gt;

&lt;p&gt;想像一个杂志类型的App，一个分页的UIScrollView，每页显示一个UIImageView，一旦某一页进入屏幕区域你就要为这个页创建或者重用一个UIImageView并把它放到scrollView的当前显示区域，即使这个页只有一个像素进入到屏幕区域，你还是要做这些工作。这在模拟器上运行得非常好，但在真机上进行测试，你会发现每次进入下一页时都会有一个明显的延迟。这个延迟来自于将图片从文件解压缩并渲染到屏幕上这一系列的工作。不幸的是UIImage仅在图片将要显示的时候做这个解压工作。&lt;/p&gt;

&lt;p&gt;因为添加一个view到当前的view层次结构中必须在主线程上进行，所以图片的解压缩和之后渲染到屏幕上的工作也在主线程进行，这就是这个延迟产生的原因，这个问题也可以在store里的其他有类似这种效果的app中发现。&lt;/p&gt;

&lt;p&gt;一般我们使用的图片有两种主要格式，jpeg和png。Apple通常推荐你使用png作为用户界面的图片格式，这些图片会被一个叫&lt;a href=&quot;http://pmt.sourceforge.net/pngcrush/&quot;&gt;pngcrush&lt;/a&gt;开源的工具优化(译者注:这个工具就在/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/pngcrush )，这样对于iOS设备就可以在显示时更快地进行解压和渲染。iPad平台上首批出现的杂志应用，比如Wired，就曾用过png作为杂志内容图片的格式，这导致了这个应用的某一版本大小超过了500MB(link)[http://www.cocoanetics.com/2010/05/saturday-morning-breakfast-wired-emag/]&lt;/p&gt;

&lt;p&gt;虽然png格式的图片会被事先优化好，但是这并不意味着在所有情况下png都是最佳的图片格式，png对于那些app中自带的图片来说非常好，但是对于要从internet上down下来的图片来说又会怎样呢。png和jpeg这两种格式都有各自的优缺点：&lt;/p&gt;

&lt;p&gt;png格式的图片有alpha通道，jpeg则没有。png无损压缩，jpeg允许你选择0-100%的压缩质量。如果需要alpha通道(透明)，就只能用png格式。但是如果你不需要一个完美的图片，就可以使用jpeg格式，jpeg格式会忽略那些你看不到的信息，对于大部分的图片可以使用60-70%的压缩质量而不对图片造成明显的影响，对于比如文字那样有”sharp pixels”的图片就可能需要较高的压缩质量，对于照片可以使用较低的压缩质量。&lt;/p&gt;

&lt;p&gt;来看一下一个图片的空间消耗：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  1. 磁盘空间或者通过internet传输所消耗的空间

  2. 解压缩空间，通常是长X宽X高X4字节（RGBA）

  3. 当显示在一个view中时，view本身也需要空间来存储layer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;对于这里的第一个问题，有一个可能的优化方法：将压缩的文件拷贝到内存中不如映射到内存中，NSData有能力来假设一块磁盘空间是在内存中的，这样当访问这个图片时实际上就是从磁盘访问而不是从内存。据说CGImage知道哪种访问方式是最高效的，UIImage只是将CGImage封装了一下。&lt;/p&gt;

&lt;p&gt;对于“将这些像素显示到屏幕上最快要多久？”这个问题，显示一个图片所消耗的时间由以下三个因素决定：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  1. 从磁盘上alloc/init UIImage的时间

  2. 解压缩的时间

  3. 将解压缩后的比特转换成CGContext的时间，通常需要改变尺寸，混合，抗锯齿工作。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;要逐一解答各个问题，我们需要一个benchmark来测量。&lt;/p&gt;

&lt;h2 id=&quot;测试环境和测试内容&quot;&gt;测试环境和测试内容&lt;/h2&gt;

&lt;p&gt;我做了一个在iOS设备上运行的&lt;a href=&quot;https://github.com/Cocoanetics/Cocoanetics-Benchmarks&quot;&gt;benchmark app&lt;/a&gt;。对优化和未优化的png图片以及不同尺寸的图片进行了测试，最小时间单位为1ms，不是特别精确，但已经有足够的参考价值了。&lt;/p&gt;

&lt;p&gt;测试包括128×96, 256×192, 512×384, 1024×768 和 2048×1536这几种比较有代表性的分辨率，以及优化过的png，未优化的png，压缩质量从10-100%的jpeg这几种格式。benchmark运行在iPad 1+2，iPhone3G，iPhone3G，iPhone4上。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://longtimenoc.com/wordpress/wp-content/uploads/2012/01/iOSFlower_2048x1536.90-300x225.jpg&quot; alt=&quot;Flower 2048x1536 90 300x225&quot; /&gt;&lt;/p&gt;

&lt;p&gt;以下为各个设备的硬件参数，来自Wikipedia：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  * iPhone 3G:Samsung 32-bit RISC ARM11 620 MHz 处理器 (降频到 412 MHz), PowerVR MBX Lite 3D GPU, 128 MB eDRAM
  * iPhone 3GS: Samsung APL0298C05 芯片，ARM Cortex-A8架构，降频到600MHz(从833MHz)，集成PowerVR SGX 535 GPU，256 MB eDRAM。
  * iPhone 4:基于ARM Cortex-A8的Apple A4芯片，集成 PowerVR SGX 535 GPU，在iPad中频率为1GHz，iPhone 4中的频率没有披露(译者注：不都说是800MHz么，还有512MB RAM都忘了写了，不过这些不说大家也知道)
  * iPad 1:1GHz Apple A4芯片 256MB DDR Ram (译者吐槽：原文写的是256GB，吾派的壮哉！)
  * iPad 2:1GHz 双核Apple A5芯片，512MB DDR2 RAM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这其中iPad 1和iPhone 4有相同的处理器，在Apple使用自家的芯片后我们看到了性能的明显提升，锁频的A4比之前的Cortex-A8+PowerVR SGC 535 GPU要快一倍&lt;/p&gt;

&lt;h2 id=&quot;测试数据&quot;&gt;测试数据&lt;/h2&gt;

&lt;p&gt;1024×768分辨率，90%压缩质量的jpeg图片从加载，解压缩到渲染的时间：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;* iPhone 3G: 527 ms
* iPhone 3GS: 134 ms
* iPad: 79 ms
* iPhone 4: 70 ms
* iPad 2: 51 ms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;同样是1024×768分辨率，对比优化和未优化的PNG图片&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;* iPhone 3G: 866 ms – 1032 ms = 快16%
* iPhone 3GS: 249 ms – 458 ms = 快46%
* iPad: 130 ms – 256 ms = 快49%
* iPhone 4: 179 ms – 309 ms = 快42%
* iPad 2: 105 ms – 208 ms = 快49%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;3GS的数据充分体现了优化过的png好处：比未优化的快一倍。&lt;/p&gt;

&lt;p&gt;以下的图表记录了所有测试数据。&lt;/p&gt;

&lt;p&gt;我们首先可以发现同一图表中(相同分辨率)不同的压缩质量有着相似的时间开销，为了数据的完整我还是把所有数据都提供出来：&lt;/p&gt;

&lt;h6&gt;&lt;img src=&quot;http://longtimenoc.com/wordpress/wp-content/uploads/2012/01/iOSChart_0256.png&quot; alt=&quot;Chart 0256&quot; /&gt;&lt;img src=&quot;http://longtimenoc.com/wordpress/wp-content/uploads/2012/01/iOSChart_0128.png&quot; alt=&quot;Chart 0128&quot; /&gt;&lt;/h6&gt;

&lt;p&gt;这两张图表代表了那些可能用在用户界面中的图片。忽略那个古老的设备，我们可一看到所有格式基本都在20ms左右完成显示，这个时间是图片足够小以便即时显示的下限。如果你有一个古老的设备而又不想让你的App很卡的话就要把解压缩工作放到主线程之外进行。&lt;/p&gt;

&lt;p&gt;以下的三张图表测试的是那些拥有可以充满iPhone，iPad屏幕的分辨率的图片。&lt;/p&gt;

&lt;h6 id=&quot;-1&quot;&gt;&lt;img src=&quot;http://longtimenoc.com/wordpress/wp-content/uploads/2012/01/iOSChart_0512.png&quot; alt=&quot;Chart 0512&quot; /&gt;&lt;/h6&gt;

&lt;p&gt;到此之前如果我们忽略古老设备的话，大部分图片都能很快显示，我们可以看到这种条件下使用png图片会对性能造成冲击，我们会更倾向于使用jpeg。&lt;/p&gt;

&lt;h6 id=&quot;-2&quot;&gt;&lt;img src=&quot;http://longtimenoc.com/wordpress/wp-content/uploads/2012/01/iOSChart_1024.png&quot; alt=&quot;Chart 1024&quot; /&gt;&lt;/h6&gt;

&lt;p&gt;&lt;img src=&quot;http://longtimenoc.com/wordpress/wp-content/uploads/2012/01/iOSChart_2048.png&quot; alt=&quot;Chart 2048&quot; /&gt;&lt;/p&gt;

&lt;p&gt;这些分辨率下即使最快的设备每秒也只能处理2(iPad Retina全屏)／10(iPad全屏)张大图片。&lt;/p&gt;

&lt;p&gt;即使在非主线程上进行解压缩工作，绘制图片仍需要消耗可观的时间，你可能应该将图片分成小块并使用CATiledLayer来完成显示。&lt;/p&gt;

&lt;p&gt;综上我们可一看到红色区域(解压缩)总是消耗最多时间的部分，渲染(绘制)的时间仅取决于分辨率而不是压缩质量，因为像素占组要因素。&lt;/p&gt;

&lt;p&gt;通常100%质量的jpeg和优化过的png图片时间开销大致相同。我可以想到两个使用jpeg的理由：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1）在设备上不能动态创建优化过的png 
2）你只是需要一个完美的图片而不需要考虑磁盘空间开销
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;横向对比文件大小(文件大小的图表在下面)，可以看到从jpeg 10%到jpeg 90%的时间开销线性增长。&lt;/p&gt;

&lt;p&gt;在最后这张图表中有一个有趣的问题，在未来可能Retina Display iPad设备上，我们所用的图片的解码时间应当比iPad 2快3－4倍(因为我们需要让图片即时显示在双倍分辨率屏目上，也就是比之前多3倍的像素)，而从iPad 1到iPad 2仅有一倍的性能提升，所以这就是iPad 2还不能支持Retina显示的原因。&lt;/p&gt;

&lt;h2 id=&quot;文件大小&quot;&gt;文件大小&lt;/h2&gt;

&lt;p&gt;让我们看一下文件大小，优化过的png图片渲染起来更快，但是它减小了文件大小么？&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://longtimenoc.com/wordpress/wp-content/uploads/2012/01/iOSScreen-Shot-2011-09-30-at-5.08.04-PM.png&quot; alt=&quot;Screen Shot 2011 09 30 at 5 08 04 PM&quot; /&gt;&lt;/p&gt;

&lt;p&gt;优化过的png格式仅仅对大尺寸图片的文件大小有少量减小，100%压缩质量的jpeg图片文件大小比优化过的png要小，但是100%的质量似乎失去了压缩的目的。我们可一看到使用90%压缩质量的文件要比100%压缩质量的文件小一半还多，jpeg格式的文件大小从10%到90%线性增长，但从90%到100%却有个巨大的增加。&lt;/p&gt;

&lt;h2 id=&quot;即时性&quot;&gt;即时性？&lt;/h2&gt;

&lt;p&gt;对于全屏尺寸的图片我们可以发现一个自从Apple推出平板设备以来就有的一个问题：一个70%压缩质量的全屏尺寸图片在iPad 1上显示需要高达75ms，iPad 2上仍要49ms，完全不能满足即时显示的要求。这与我们60fps的目标相差甚远，13fps或20fps与让人感觉流畅的30祯相比也有很大差距。这会导致在我们拖动scrollview，新图片进入屏幕时，将会卡20分之一秒，之后scrollview必须跳动来追赶上你的手势。&lt;/p&gt;

&lt;p&gt;如果排除解压缩的时间，结果就比之前强多了，17－18ms的时间将带来大约55fps的流畅度。有趣的是两代iPad将像素混合到layer的时间没有多少区别，区别仅在解压缩上。&lt;/p&gt;

&lt;p&gt;对此我在iCatalog中绘制catalog页的一个简单解决方法就是使用CATiledLayer，并禁用fading。这样就可以在后台线程处理图片的显示而不影响scroll的性能。当然如果快速向右滑动（scroll），相应页的显示就会有一个明显的延迟。这种解决方法的缺点就是很难将横竖屏切换做得很好。&lt;/p&gt;

&lt;p&gt;一个更先进的方法就是提前强制解压缩图片。&lt;/p&gt;

&lt;h2 id=&quot;强制解压缩&quot;&gt;强制解压缩&lt;/h2&gt;

&lt;p&gt;当第一次使用图片时，iOS会解压它。通常这个解压缩后的版本将滞留一段时间（内存允许）。尽管这么做没什么意义，但你可以通过将图片渲染成一个新的图片来解压缩这个图片。这样你将在一小段时间内获得&lt;strong&gt;两个&lt;/strong&gt;解压缩的版本。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;- (void)decompressImage:(UIImage *)image
{
UIGraphicsBeginImageContext(CGSizeMake(1, 1));
[image drawAtPoint:CGPointZero];
UIGraphicsEndImageContext();
}
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这一段代码会解压缩这个image，即时它只有一个像素。&lt;/p&gt;

&lt;p&gt;奇怪的是如果UIImage只是通过initWithContentsOfFile创建的，我不能始终保持这个解压缩的版本。所以我必须使用ImageIO framework(iOS 4之后可用) 中提供的一个选项来显式保持这个解压缩的版本:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSNumber 	numberWithBool:YES]
forKey:(id)kCGImageSourceShouldCache];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;CGImageSourceRef source = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, (CFDictionaryRef)dict);&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;UIImage *retImage = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CFRelease(source);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这样初始化图片就可以让解压缩仅发生一次：第一次解压缩消耗很长一段时间，第二次完全不消耗。这其中的关键就是kCGImageSourceShouldCache，你可以为CGImageSource和CGImageSourceCreateImageAtIndex使用这个选项，头文件中是这样说明的：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Specifies whether the image should be cached in a decoded form. The value of this key must be a CFBooleanRef; the default value is kCFBooleanFalse.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果这个选项设置为NO，绘制图片的时间又会随着解压缩时间增长，如果设置为YES就仅仅解压缩一次。&lt;/p&gt;

&lt;h2 id=&quot;结论&quot;&gt;结论&lt;/h2&gt;

&lt;p&gt;如果你需要alpha通道或者必须使用PNG格式，那么我推荐你在你的web服务器上安装pngcrush并处理好所有的png图片。其他情况下，高质量的jpeg能带来较小的文件大小以及更快的解压缩和渲染。&lt;/p&gt;

&lt;p&gt;事实证明，png格式对于那些使用在UI元素中的小图片来说非常好，但是对于那些全屏显示图片的应用来说则完全不是。替代png的通常是60-80%压缩质量的jpeg，至于压缩质量取多少合适，这取决于你的图片内容。&lt;/p&gt;

&lt;p&gt;你可能希望所有显示过的图片都能保持他们的解压缩版本，但是这也将带来大量的内存开销并导致你的App进程被杀掉。此时使用NSCache就是一个很好的解决方案。它可以自动在内存短缺的时候照看好这些图片。&lt;/p&gt;

&lt;p&gt;虽然不幸的是我们不能知道一个图片是否需要解压缩，同样一个图片的解压缩版本消失时我们也不会获得任何通知（这或许非常适合提交到Apple的bug反馈网站上）。但幸运的是，通过上述方法访问的解压缩后的图片不会再在解压缩上消耗时间。所以你可以同时在恰当的时间和恰当的条件下使用这种方法而不造成额外的开销。&lt;/p&gt;

&lt;p&gt;——OVER——&lt;/p&gt;

&lt;p&gt;这里还要说的是，如果你的图片很大，可能还需要做其他的工作，比如可以牺牲一下及时性来换取流畅的滚动的话，延迟加载（取消实时的绘制，待tableView滚动停止后才对cell中的UIImageView进行绘制）也是一个可参考的方案。&lt;/p&gt;

&lt;p&gt;感谢&lt;strong&gt;ultragtx&lt;/strong&gt;的辛勤劳动，这里附上&lt;a href=&quot;http://longtimenoc.com/archives/ios%E5%A6%82%E4%BD%95%E9%81%BF%E5%85%8D%E5%9B%BE%E5%83%8F%E8%A7%A3%E5%8E%8B%E7%BC%A9%E7%9A%84%E6%97%B6%E9%97%B4%E5%BC%80%E9%94%80&quot;&gt;原文&lt;/a&gt;的连接。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>NSRunloop的简单认识</title>
   <link href="http://blog.inico.me/2013/05/03/something_nsrunloop"/>
   <updated>2013-05-03T22:58:38+00:00</updated>
   <id>http://blog.inico.me/2013/05/03/something_nsrunloop</id>
   <content type="html">&lt;p&gt;最早接触runloop的概念，是第一次用NSTimer的时候。一个最简单的例子:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1
                                              target:self
                                            selector:@selector(printMessage:)
                                            userInfo:nil
                                             repeats:YES];
//    [[NSRunLoop currentRunLoop] addTimer:timer
//                                 forMode:NSRunLoopCommonModes];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;如果我们同时在界面上滚动一个scrollview,那么我们会发现在滚动停止之前，控制台是不会有输出的，就好像scrollView在滚动的时候将timer暂停了一样。通过了解后发现，其实是Cocoa的RunLoop Mode在作怪。&lt;/p&gt;

&lt;p&gt;我把runloop理解为一种cocoa下的一种消息循环的机制，用来处理各种消息事件。我们在开发的时候一般并不需要手动去创建一个runloop，因为在程序进入mainThread之后其实就为我们创建了默认的的mainRunLoop，通过[NSRunloop currentRunLoop]我们就可以得到当前线程对应的RunLoop对象，而我们需要留意的是在多个runloop之间消息的通知方式。&lt;/p&gt;

&lt;p&gt;接上面说到的，开启一个NSTimer实质上是&lt;del&gt;开启了一个新的线程(Runloop)&lt;/del&gt;在当前Runloop中注册了一个新的事件源，&lt;del&gt;也就是说除了MainRunloop之外还有一个Runloop存在&lt;/del&gt;。而当scrollView在滚动的时候，当前MainRunLoop是处于UITrackingRunLoopMode，在该模式下，不会处理 NSDefaultRunLoopMode的消息（因为Runloop Model不一致），而NSTimer在创建后的RunLoop(B)默认会以NSDefaultRunLoopMode与当前context的Runloop(A)&lt;del&gt;发送消息&lt;/del&gt;进行通信。要想在scrollView滚动的同时也接受其他runloop的消息，则需要改变两者之间的RunLoopMode&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; [[NSRunLoop currentRunLoop] addTimer:timer
                              forMode:NSRunLoopCommonModes];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;类似的问题在前几天修改一个http异步通信模块的时候也碰到了，简单地说是向服务器异步获取图片数据后通知主线程刷新tableView中的图片，但在tableView滚动还没有停止或用户手指还停留在屏幕上的时候，图片一直不会出来。后来发现请求数据的时候用到了NSURLConnection的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (id)initWithRequest:(NSURLRequest *)request 
             delegate:(id)delegate;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;了解后发现该方法创建的异步请求线程和NSTimer一样，也是NSDefaultRunLoopMode的，与&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (id)initWithRequest:(NSURLRequest *)request 
             delegate:(id)delegate 
     startImmediately:(BOOL)startImmediately
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;不同的是，上面的方法默认创建后默认直接发起请求，并以NSDefaultRunLoopMode与runloop进行消息传递，因此我们需要和NSTimer一样更改他的RunLoopMode。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;NSURLConnection *connection = [[NSURLConnection alloc]
                               initWithRequest:request
                               delegate:self
                               startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
            forMode:NSRunLoopCommonModes];
[connection start];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/1826913/delayed-uiimageview-rendering-in-uitableview&quot;&gt;StackOverFlow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/demon1105/RunloopDemo&quot;&gt;Github Demo&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Xcode集成Vim</title>
   <link href="http://blog.inico.me/2013/04/18/xcode_with_vim"/>
   <updated>2013-04-18T21:53:46+00:00</updated>
   <id>http://blog.inico.me/2013/04/18/xcode_with_vim</id>
   <content type="html">&lt;p&gt;介绍一个XCode插件，叫&lt;a href=&quot;https://github.com/JugglerShu/XVim&quot;&gt;XVim&lt;/a&gt;。今天一同事（汗一下，人是做android的）推荐的，之前只是偶尔傻傻地用MacVim，代码的补全确实不好用，只有一些基本语法级别补全，相对iOS下面一大推的API方法名来说根本不够用。&lt;/p&gt;

&lt;p&gt;装好插件原本的编辑窗口就变成了下面这个样子，在Editor和Console之间多了一条VI交互窗口·&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://pic.yupoo.com/demon42111915/CS0s6IQO/medish.jpg&quot; alt=&quot;XVim&quot; /&gt;&lt;/p&gt;

&lt;p&gt;如果你不想用的话可以在Edit下面去掉XVim的勾选&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://pic.yupoo.com/demon42111915/CS0s6Lyy/medish.jpg&quot; alt=&quot;XVim_select&quot; /&gt;&lt;/p&gt;

&lt;p&gt;这里对我来说有个小冲突，Vim进入交互模式是Esc，xcode的代码补全快捷方式我也习惯使用Esc(其实command+.也可以，看自己洗好了)，用了XVim之后就Esc就没截获了，可以command+,进入偏好设置，设置另外的代码不全快捷键&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://pic.yupoo.com/demon42111915/CS0s7KvZ/medish.jpg&quot; alt=&quot;Screen Shot 2013-04-18 at 9.49.40 PM&quot; /&gt;&lt;/p&gt;

&lt;p&gt;最后附上&lt;a href=&quot;https://github.com/demon1105/xcode-theme&quot;&gt;Xcode的主题&lt;/a&gt;(和我的iterm差不多一个风格)。&lt;/p&gt;

&lt;p&gt;Over&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>炒冷饭，再提一次QuincyKit</title>
   <link href="http://blog.inico.me/2013/03/28/crash_again"/>
   <updated>2013-03-28T22:51:54+00:00</updated>
   <id>http://blog.inico.me/2013/03/28/crash_again</id>
   <content type="html">&lt;p&gt;之前在&lt;a href=&quot;http://www.taofengping.com/2012/12/08/quincykit_crashreport/&quot;&gt;这篇&lt;/a&gt;里面已经提到过一次QuincyKit。换了新公司，第一件事情就是让我整理一下这个框架，写写流程结构图什么的，因为之前已经搭过好几次，所以搞起来还算顺手。这里顺带做个总结。&lt;/p&gt;

&lt;h3 id=&quot;1什么是quincykit&quot;&gt;1、什么是QuincyKit?&lt;/h3&gt;

&lt;p&gt;QuincyKit(&lt;a href=&quot;http://quincykit.net/&quot;&gt;http://quincykit.net&lt;/a&gt;) 是一个开源的，针对iOS和Mac OS X系统的实时crashReport管理系统&lt;/p&gt;

&lt;p&gt;###2、为什么用QuincyKit?&lt;/p&gt;

&lt;p&gt;或许有人会问，why QuincyKit?why not CrashReport in itunesconnect? 请问：在你的itunesconnect中曾经看到过几次CrashReport?sometime?few?or never? 就我个人来说的话，从来没有在自己的itunesconnect账户中看到过crashReport。难道是自己的App本身就没有出现过crash吗？我想不是的。 找到一篇文章(&lt;a href=&quot;http://www.techmemo.com.tw/wp/2011/02/23/553/iOS-how-to-obtain-the-users-crash-report/%29,&quot;&gt;http://www.techmemo.com.tw/wp/2011/02/23/553/iOS-how-to-obtain-the-users-crash-report/),&lt;/a&gt; 文章提到， 在itunesconnect中的日志，并不是无条件自动通过iOS设备把crashlog提交到Apple。当用户的iOS设备插上电脑，itunes会询问用户：是否要协助Apple改进它的产品质量？问题就出在这里，如果选择了NO，crashLog就不会提交到itunesconnect。并且这以后itunes也不会再询问你的意见， 所以itunesconnect就拿不到crashlog了。&lt;/p&gt;

&lt;p&gt;###3、QuincyKit的特点&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;A:自动发送crashlog到服务端数据库（可选后台自动发布或用户选择性提交）
B:提供简单的管理界面访问数据库
C:提供脚本解析批量解析crashLog（需要在包含对应.dSYM文件的Mac端运行）
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;###4、QuincyKit工作的大致的流程&lt;/p&gt;

&lt;p&gt;客户端每次运行时检查当前App的crash路径&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[[NSString stringWithFormat:@&quot;%@&quot;, [[paths objectAtIndex:0]                       stringByAppendingPathComponent:@&quot;/crashes/&quot;]]) 下的日志文件，如果有新的未提交的crashlog,则post到开发者自己的服务器,写入数据库（未经过symbolicateCrash）。服务端可通过web管理界面查看对应程序(通过bundle区分，同一个App可根据version区分)的crash日志。如果要在web界面直接呈现symbolicateCrash之后的信息，则需要web管理界面开启相应App的symbolicate选项，然后在Mac端（有xcode clt，需atos命令）上运行symbolicate.php。他会将上文中提到数据库中的crash日志抓取到本地后尝试用atos命令对地址进行解释，完成后将结果再写入数据库，这样我们重新在web端再看到的crashlog将会是处理过之后的内容。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;PS:&lt;/p&gt;

&lt;p&gt;顺带解决了之前提到的remote symbolicatecrash的问题，原来是之前在写Host地址的时候带上了子路径，看了symbolicate.php中的源码后发现在config里只能是&lt;a href=&quot;https://github.com/TheRealKerni/QuincyKit/issues/127&quot;&gt;纯粹的主机地址&lt;/a&gt;（因为丫很单纯地在host后面加了个:端口）····&lt;/p&gt;

&lt;p&gt;搞定。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>晒LeapMotion</title>
   <link href="http://blog.inico.me/2013/03/13/show_leapmotion"/>
   <updated>2013-03-13T21:53:31+00:00</updated>
   <id>http://blog.inico.me/2013/03/13/show_leapmotion</id>
   <content type="html">&lt;p&gt;其实上周就寄到了，发出到收到大概隔了一周吧，FedEx还算给力。因为忙着工作交接的事情就给忘了。&lt;/p&gt;

&lt;p&gt;到手后拆开里面有一个感应器，一个USB传输线，还有一封LeapMotion CEO Michael Buckwald写的信。大致内容应该是感觉对Leap的支持（我也感谢你们啊，哈哈！互利互补么），让我们一起努力建设Leap社区之类的东西。&lt;/p&gt;

&lt;p&gt;上图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://pic.yupoo.com/demon42111915/CS0rXWTM/medish.jpg&quot; alt=&quot;Back&quot; /&gt;&lt;/p&gt;

&lt;p&gt;拆完后先把之前下载的SDK在Mac上安装了一下，打开后发现要更新，就按照步骤选择更新了。不过网速很慢，过了很久才更新到一半。按耐不住寂寞我就直接连上了USB，会提示激活设备（输入你在Leap Developer注册的账号）。运行了几个Demo程序后发现居然没有用！！！首先想到的是难道是因为SDK没有更新到最新版的原因？再一想不应该啊！拿起Leap翻过来一看，卧槽····放反了，下面这张图才是Leap的正面图···真尼玛蠢！&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://pic.yupoo.com/demon42111915/CS0s62QE/medish.jpg&quot; alt=&quot;Front&quot; /&gt;&lt;/p&gt;

&lt;p&gt;然后把所有的Demo都跑了个遍，发现好像对单手多指的握拳（松手）的识别不是很好，多指的时候容易出现错误，单是单指的识别率精度很高（可以写写字什么的）。所以如果用来写个类似FruitNinja的游戏的话(针对个人PC平台，区别于Xbox这种家庭娱乐中心)，感觉在体验上应该会还不错。&lt;/p&gt;

&lt;p&gt;毕竟Kinect只能识别躯干这些（腿，手臂）的动作，对于手指什么的就无能为力了。但是看到有些人把Kinect和Leap放在同于个平台上来对比，感觉似乎不是合适。前者的适用范围是在大的空间里识别人体躯干动作，一个是小空间内识别例如手指的运动。感觉各有长处吧。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>LeapMotion开发者计划</title>
   <link href="http://blog.inico.me/2013/03/04/leapmotion_dev_apply"/>
   <updated>2013-03-04T20:22:01+00:00</updated>
   <id>http://blog.inico.me/2013/03/04/leapmotion_dev_apply</id>
   <content type="html">&lt;p&gt;上周六收到了LeapMotion发过来邮件，大致的意思是开发者资格审核已经批准，让我补充一下地址相关信息，以便他们发送开发版过来。小激动了一下，今天抽个空把申请的过程大致说一下。&lt;/p&gt;

&lt;p&gt;其实年前就开始关注&lt;a href=&quot;https://www.leapmotion.com/&quot;&gt;LeapMotion&lt;/a&gt;，觉得这货除了牛逼还是牛逼，但因为目前还没有正式发行，想入一个的话只能预定。&lt;/p&gt;

&lt;p&gt;因为前几天在微博上看到一位朋友收到了LeapMotion的开发版，于是赶紧去官网找找看入口（&lt;a href=&quot;https://www.leapmotion.com/developers&quot;&gt;Developer wanted&lt;/a&gt;）。这里写道：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Our revolutionary technology is changing the way people interact with computers forever. We're looking for talented developers who are just as passionate as we are.

We're shipping over 10,000 Leap Motion dev units to developers across the globe so they can build groundbreaking software for our app store. Thinking about joining us? Here are some of the benefits:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;大致的意思就是leapMotion提供了1w个免费的设备给全球的开发者提前体验……..&lt;/p&gt;

&lt;p&gt;在右边找到注册的入口后，用自己常用的邮箱注册，之后会收到一封验证邮件。点击邮箱里的地址后，我们接下来要填写一些信息，具体哪几条我忘记了，但大致如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 大致说说你想开发一个什么样的项目
2. 你通常开发哪类应用
3. 你的公司名字（我记得是有这项的，个人开发者的话随便写吧）
4. 你的项目地址（github地址，作为一个开发者的话，没有github主页真的就不能和国际接轨了）
5. 你的个人website（同样，没有这个你也算脱轨···[TexturePacker](http://www.codeandweb.com/texturepacker)也是通过这个途径拿到的免费证书）
6. 你用的一些开发语言有哪些
7. 还有什么···记不全了 填好之后，提交···我记得提交完之后就没有反馈了，邮箱也没有收到什么确认邮件。大概过了一个星期，收到了文章开头提到的邮件···
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;其实还没完，因为没有正真收到LeapMotion。拿到了到时候再来晒晒体验以及感受···&lt;/p&gt;

&lt;p&gt;好期待！！！&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>KVC_KVO</title>
   <link href="http://blog.inico.me/2013/02/20/kvc_kvo"/>
   <updated>2013-02-20T23:29:55+00:00</updated>
   <id>http://blog.inico.me/2013/02/20/kvc_kvo</id>
   <content type="html">&lt;p&gt;记得刚开始写objc的时候，从NSDictionary中获取数据的时候objectForKey和valueForKey是乱用的，想到用哪个就用哪个，反正返回的东西都是一样的。这几天看了一下KVC和KVO的东西，顺带也把之前的疑问也一起解决了。&lt;/p&gt;

&lt;p&gt;首先NSDictionary的objectForKey方法是属于NSDictionary的实例方法，而valueForKey则是KVC分类(NSObject(NSKeyValueCoding))下的方法，应该说只要是继承NSObject的对象，都拥有这个方法。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;NSObject* obj = [[[NSObject alloc] init] autorelease];
NSDictionary * dic = @[@&quot;key&quot;:obj];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;del&gt;拿dic这个对象来说，[obj valueForKey:@”key”]和[obj objectForKey:@”key”]，返回的东西的确是相同的，但是如果这个Key不存在的情况下&amp;lt;key1,key2…&amp;gt;，objectForKey则返回Nil，valueForKey则会报错：&lt;/del&gt;
拿dic这个对象来说，[obj valueForKey:@”key”]和[obj objectForKey:@”key”]，返回的东西的确是相同的，我们继续看一下文档对这两个方法分别的说明：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (id)objectForKey:(id)aKey
Returns the value associated with a given key.

- (id)valueForKey:(NSString *)key
Returns the value associated with a given key.

If key does not start with “@”, invokes [objectForKey:].
If key does start with “@”, strips the “@” and invokes [super valueForKey:] with the rest of the key.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;也就是说假如我们的key不以@起头,valueForKey就是ObjectForKey一样。反之（@”@key”），则会调用super的KVC方法，valueForKey。那我们就会得到如下的结果：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[&amp;lt;__NSCFDictionary 0x892fd80&amp;gt; valueForUndefinedKey:]: this class is not key value coding-compliant for the key theKey.’
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里涉及到KVC(&lt;strong&gt;Key-Value Coding&lt;/strong&gt;)的内容。简单地说在 KVC是一种间接访问对象属性（用字符串表征）的机制 ，我们可以通过查找对象accessor的同名字符串来获取对应的值，当然也可以在字典里取到相应key的一个value。KVC这样的设计，在我理解看来，所有对象都可以理解成字典。对象自身的property的取值和赋值都可以通过valueForKey和setValue:ForKey来进行（前提是这个Key&lt;对象内部的属性&gt;必须存在）。&lt;/对象内部的属性&gt;&lt;/p&gt;

&lt;p&gt;而KVO(&lt;strong&gt;Key-Value Observing&lt;/strong&gt;)则基于KVC（只有符合KVC标准的对象才能试用KVO，继承NSObject的都可以），一种可以让我们观察对象内部属性变化的机制。听上去有点像通知(NSNotification)，但与通知不同的是，这个消息的post是由cocoa内部实现的，一旦属性发生变化我们就可以在添加observer的位置得到响应。&lt;/p&gt;

&lt;p&gt;附上一篇比较详细的&lt;a href=&quot;http://www.cnblogs.com/dark-angel/archive/2011/05/05/2037734.html&quot;&gt;参考文章&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>写在除夕前</title>
   <link href="http://blog.inico.me/2013/02/08/year_summary"/>
   <updated>2013-02-08T16:42:31+00:00</updated>
   <id>http://blog.inico.me/2013/02/08/year_summary</id>
   <content type="html">&lt;p&gt;有段时间没有写日志了，年底公司的项目上线，各种性能的改善，错误日志的排查，不管怎样，游戏最后总算上线了。&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;明天就是除夕了，这一年感觉过得真的很快。&lt;/p&gt;

&lt;p&gt;以前还在学校的时候老师总会布置一个年终总结或者学期总结的作业，那时候总是很讨厌这类的事情，不知道大家是不是都一样。有一次回家偶尔翻到以前的作业本（虽然大多数都当废纸卖了，偶尔有一些幸存的），感觉怎么一下子我就毕业了快两年了呢，于是问自己，这两年自己都成长了什么呢？学会了什么，又得到了什么呢？&lt;/p&gt;

&lt;p&gt;有个同学，到年底（12月底）的时候，都会在QQ上发一条消息过来问：今年你得到了什么，又失去了什么？起初只是觉得他心血来潮，问问而已，但不知不觉这个习惯已经坚持了三四年了，今年他还没发给我的时候，其实我也早早开始准备答案，算是对自己2012年的一个交代。&lt;/p&gt;

&lt;p&gt;上面提到的几件事情放在在一起看看，似乎就存在一些联系，自己又说不清是什么。或许随着岁月的流逝，这种情感会变得越来越浓厚，于是就有了这篇文章。&lt;/p&gt;

&lt;p&gt;回过头来看自己，不知不觉来到这个团队已经第三个年头了。目前为止，过去一年间虽然团队只推出了项目（&lt;a href=&quot;http://app.91.com/Soft/iPhone/com.glee.heroxcn91-1.0-1.0.html&quot;&gt;黑暗之光&lt;/a&gt;）,但是对我自己处于的客户端开发的部门来说的话可谓是：历经磨难，来来回回同一个界面上的修改不下5遍（祭坛，英雄学院应该不止）。自己能苟延残喘活下来感觉已是相当不容易了，这里不得不说一句，团队的项的管理太糟糕，各种图片资源没有人去做统一梳理（svn上的图片资源比较混乱），数值没有统一的记录（很多都是口头说一下，到时候出了问题就无从查起了）等等太多的事情。缓过来来想想，开发的技术点差不多都是已有的几个来来回回折腾，自己在这个项目中开发过程中的能力并不见得有太大的提升。&lt;/p&gt;

&lt;p&gt;反倒是自己在做其他的几个小项目的时候接触到了比较多的新的东西，比如phoneGap，比如在Github上一些很好的开源框架，还有自己通过对一些开源框架的解读后，改写的一些脚本工具什么的。但因为是公司的项目太过于保守，一些东西也只有在自己的项目里用着，感觉的确给自己省了很多体力劳动。同时也让自己对项目的开发过程中，对一些模块的组织，以及项目结构性上的东西有了新的认识。&lt;/p&gt;

&lt;p&gt;脱离团队中的话题，自己在今年也断断续续开发了三个小的项目。第一个是&lt;a href=&quot;https://itunes.apple.com/cn/app/ji-xiang-zhai/id540975204?mt=8&quot;&gt;吉祥斋&lt;/a&gt;，这是一个朋友介绍的项目，在这个项目里实现了一个全景模拟的效果，以及模拟水波的一个鱼塘小应用，用到了一点点openGL的东西，也顺带了解了一下openGL的知识。七项目月份开始开发，九月份结束，后来也更新了两三个版本，但最后因为需求方迟迟不肯把最后的一点尾款发过来，还要求做一个iPad的版本，觉得太不靠谱了，算是结束了开发。&lt;/p&gt;

&lt;p&gt;第二个是帮母校的几个学弟们做的小游戏，叫naughtyBird，游戏操作方式有些类似fruitNinja，准备年后上线，基本的开发已经结束，11月份底左右开始，到现在差不多也两个月。其实刚开始是不想做的，但后来想想他们没毕业，所以资源还有圈子也有限，自己反正也闲着，做就做吧。开发的过程中一最深的感触就是很多东西都要手把手教他们，比如切图什么的，还有命名，游戏里的规则，体验性的东西，到最后发现真是太累了。不过还好最后游戏还是出来了，不过我个人不对这个游戏报很大的期望，其一是因为美术的感觉还差那么一点感觉，游戏的玩法也没有很大的创新，可能是因为经验有限，我自己的时间也比较有限吧。感觉要真正做好一个产品，没有把自己全部的精力放上去是肯定不行的。&lt;/p&gt;

&lt;p&gt;第三个就是&lt;a href=&quot;http://www.awaitoo.com/&quot;&gt;等待网&lt;/a&gt;了，这个项目的设计就是文章里第一个项目吉祥斋的设计团队，起初觉得等待网的点子还挺有意思的，于是叫我加入一起来做，我也斗志满满。但后来发现做着做着发现有一个通病：他们想做一个东西，功能点什么都在，但是界面交互还有功能的组织上考虑不周全，或者根本就没有考虑到，因为web的开发在天津，很多事情沟通上不是很方便。从12月初开始开发到目前为止，差不多完成了客户端所有界面的一些内容（大致1/3的工作量），目前还在做一些接口的调试还有数据的接入，以及业务逻辑上的一些工作，时间上允许的话应该3月初可以提交至appStore。总之也是比较纠结的过程。&lt;/p&gt;

&lt;p&gt;说了这么多，想想自己也算做的几个项目。但是自己知道，目前为止自己不过是一个技术上的熟练工，开发时遇到的困难还有知识点，也并没有全部都系统性地去认识他们，所以期望来年可以做一些技术性的沉淀工作：多阅读，多进步。再者就是找到一个靠谱点的公司，换个平台看看，扩大自己的圈子，接触一些新的知识点，或许对自己还有今后的规划也会有一个新的认识。然后其他的事情都先抛到后面再说，投资自己也是一种投资，难道不是么？:D&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>UIView动画播放的一些认识</title>
   <link href="http://blog.inico.me/2013/01/08/uiview_something_interactive"/>
   <updated>2013-01-08T20:58:45+00:00</updated>
   <id>http://blog.inico.me/2013/01/08/uiview_something_interactive</id>
   <content type="html">&lt;p&gt;如果对一个UIView做一个动画，刚开始都是用最原始的写法：&lt;/p&gt;

&lt;p&gt;在[UIView beginAnimations:nil context:NULL] 后设置好动画的一些属性之后，[UIView commitAnimations]然后播放，之后用了Block之后发现原来可以这么简单，最简单的动画一句话就可以搞定&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;+ (void)animateWithDuration:(NSTimeInterval)duration 
				  animations:(void (^)	(void))animations
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;于是就一直这么用了。但直到前几天才发现如果这么用的话，应用在5.0之前的系统跑可能是有问题的。&lt;/p&gt;

&lt;p&gt;假如我们在播放动画的同时，需要相应交互的事件，那么5.0之前就必须设置相应的UIViewAnimationOptions，&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;+ (void)animateWithDuration:(NSTimeInterval)duration
				      delay:(NSTimeInterval)delay
			        options:(UIViewAnimationOptions)options 
				 animations:(void (^)(void))animations 
  				 completion:(void (^)(BOOL finished))completion
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;因为在5.0之前，动画播放的时候，系统会把整个应用内所有的事件相应都停止，在苹果的官方&lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/clm/UIView/animateWithDuration:delay:options:animations:completion:&quot;&gt;document&lt;/a&gt;里也可以找到说明：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;During an animation, user interactions are temporarily disabled for the views being animated. (Prior to iOS 5, user interactions are disabled for the entire application.)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;假设你的动画时间很长（循环播放淡出淡出等等），那有会造成界面好像卡在那边，不管你怎么点击，事件都不会得到相应。(&lt;a href=&quot;http://stackoverflow.com/questions/3897279/difference-between-uiview-beginanimationscontext-and-uiview-animatewithdura&quot;&gt;stackOverFlow&lt;/a&gt;)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>UIScrollView touchEvent的一些认识</title>
   <link href="http://blog.inico.me/2013/01/07/uiscrollview-touchevent_something"/>
   <updated>2013-01-07T20:52:28+00:00</updated>
   <id>http://blog.inico.me/2013/01/07/uiscrollview-touchevent_something</id>
   <content type="html">&lt;p&gt;之前在做东西的时候用到了UIScrollView，只是单纯地将它作为一个可滚动的容器来使用，并没有对他以及子视图的touch事件处理进行过了解。其实很好奇如果在UIScrollView的子子视图上要处理自身的touchEvent的话，它是怎么工作的呢？&lt;/p&gt;

&lt;p&gt;一个简单的例子，假如我们在UIScrollView上添加的子视图需要相应自己的事件，假如是一个UIButton，在点击的时候的确也能够相应的动作，并且UIScrollView的滚动事件也能正常响应，但是如果细心观察的话我们可以发现，button的事件并不立即做出相应的，有一个很短的延迟。&lt;/p&gt;

&lt;p&gt;而这时候如果我们的UIButton设置了高亮状态，点击后实现的界面跳转的动作，注册的事件是touchUpInside，那就可能没法看到高亮后的按钮就直接执行界面跳转了。&lt;/p&gt;

&lt;p&gt;造成事件响应的延迟的原因就是因为UIScrollView再接收到事件触发的时候，需要判断这个touch到底是应该传递下去还是自己处理以便滑动。&lt;/p&gt;

&lt;p&gt;假如我们将UIScrollView delaysContentTouches属性设置为NO,那么这个延迟就不存在了，但于此同时，恰好touch在子视图上被接收，那不管怎么滑动界面，界面都不再滚动。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@property(nonatomic) BOOL delaysContentTouches;       
// default is YES. if NO, we immediately call -touchesShouldBegin:withEvent:inContentView:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;当然如果我们要在滑动的时候可以获得事件也是可以的，通过重写touchesShouldCancelInContentView方法可以实现。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// called before scrolling begins if touches have already been delivered to
// a subview of the scroll view. if it returns NO the touches will continue
// to be delivered to the subview and scrolling will not occur
// not called if canCancelContentTouches is NO. default returns YES 
// if view isn't a UIControl
- (BOOL)touchesShouldCancelInContentView:(UIView *)view;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;简答翻译一下注释：如果touches已经被传递到当前ScrollView的某个子视图上，当滑动即将发生之前该方法会被调用。如果返回NO的话，touches将会继续重新移交至ScrollView上进行处理并且滑动事件不会被打断(前提是canCancelContentTouches[可取消内容视图的touches]为YES，如果是NO的话就不行了)，默认的情况下如果参数view不是UIControl的实例的话，总是返回YES&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>iOS Exchange google联系人延迟</title>
   <link href="http://blog.inico.me/2012/12/23/ios-exchange-google_contacts_delay"/>
   <updated>2012-12-23T13:23:27+00:00</updated>
   <id>http://blog.inico.me/2012/12/23/ios-exchange-google_contacts_delay</id>
   <content type="html">&lt;p&gt;入了ip5，做的第一件事情就是下了一堆的google app.接下来就是同步google contacts的信息了，我用的是exchange，之前一直没有出现问题。因为是日版的合约机，所以还得在号码前统一+86。这些操作我在浏览器上完成后发现手机上的联系人却迟迟没有同步过来，我想可能是网络太慢了，所以也没有在意。&lt;/p&gt;

&lt;p&gt;过了一天，发现联系人还是没有更新，我就纳闷了，查了一下悲剧了:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.evolife.cn/html/2012/68193.html&quot;&gt;http://www.evolife.cn/html/2012/68193.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;貌似用exchange的要悲剧了，不过还好IOS里面也提供了cardDAV的同步：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://support.google.com/mail/bin/answer.py?hl=en&amp;amp;answer=2753077&quot;&gt;http://support.google.com/mail/bin/answer.py?hl=en&amp;amp;answer=2753077&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;于是删了exchange的账户，重新设置了一个cardDAV，搞定···&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>UITextField与UITextView一起使用的奇怪问题</title>
   <link href="http://blog.inico.me/2012/12/11/uitextfield_uitextview_sucks"/>
   <updated>2012-12-11T18:04:49+00:00</updated>
   <id>http://blog.inico.me/2012/12/11/uitextfield_uitextview_sucks</id>
   <content type="html">&lt;p&gt;今天在修改一个界面的时候碰到了一个很奇怪的问题。&lt;/p&gt;

&lt;p&gt;当我在视图中同时使用UITextField和UITextView的时候，想通过点击keyboard的return键来实现textField到textView的焦点切换，于是在委托中重写了&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;    
&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;textFieldShouldReturn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UITextField&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;textField&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;在这里[textView becomeFirstResponder]，然后我再手动切换焦点到textField上之后，再点击return键，在textView获得焦点的同时，我发现textView中的光标也会随着操作的次数下移一行。好像在textView中自动换行了····&lt;/p&gt;

&lt;p&gt;于是我又将当前试图同时设为textView的delegate，重写了textView所有的委托方法后，debug后发现在TextView获得焦点后执行了以下三个委托方法：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;    
&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;textViewShouldBeginEditing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UITextView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;textView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;textViewDidBeginEditing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UITextView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;textView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;textViewDidChange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UITextView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;textView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;前两个方法很容易理解，但是纳闷为什么会调第三个呢···因为只是获得焦点而已，没理由textView中的文字也会发生改变额··&lt;/p&gt;

&lt;p&gt;求助google大神后在&lt;a href=&quot;http://stackoverflow.com/questions/6825558/problem-with-textfieldshouldreturn-method-when-using-uitextfield-along-with-uite&quot;&gt;StackOverFlow&lt;/a&gt;上找到了解决方案，在委托中重写textFieldShouldReturn方法时，当前的textField return之后刚好要转移焦点到textView，那这时候方法应该返回NO而不是YES。&lt;/p&gt;

&lt;p&gt;这时候在运行demo，在textField的键盘上点击return，textView也不会执行委托中的textViewDidChange方法了。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>QuincyKit的crashReport框架</title>
   <link href="http://blog.inico.me/2012/12/08/quincykit_crashreport"/>
   <updated>2012-12-08T12:46:19+00:00</updated>
   <id>http://blog.inico.me/2012/12/08/quincykit_crashreport</id>
   <content type="html">&lt;p&gt;在进行开发或者产品发布后，测试人员或者用户在进行操作的过程中难免会碰到这样或者那样的异常，有时候甚至程序直接crash，如果产品还没有发布出去，我们可以直接拿到程序的错误日志，之后可以对这些日志进行分析，找到问题所在然后改善产品质量，但如果产品已经发布出去了，可能就比较麻烦了。&lt;/p&gt;

&lt;p&gt;之前在用HockyKit的时候发现作者还有另外一个开源的项目叫&lt;a href=&quot;http://quincykit.net/&quot;&gt;QuincyKit&lt;/a&gt;,它就是专门针对产品发布后收集错误日志的一个开源框架，在&lt;a href=&quot;https://github.com/therealkerni/QuincyKit&quot;&gt;github&lt;/a&gt;上可以找到他基本的客户端demo和服务端源码，搭建起来也非常简单，一个支持php5.2以上还有Mysql的服务器就可以了。客户端部分使用了CrashReporter.framework的第三方framework,github的wiki上有详细的说明。&lt;/p&gt;

&lt;p&gt;自己搭好之后使用了一下，确实不错。但是目前为止有一点还没搞定，就是&lt;a href=&quot;https://github.com/TheRealKerni/QuincyKit/wiki/Remote-symbolication&quot;&gt;Remote symbolication&lt;/a&gt;，现在拿到crashReport之后都是直接在xcode中的Organizer中解决符号化问题的，也就是&lt;a href=&quot;https://github.com/TheRealKerni/QuincyKit/wiki/Symbolication-via-Xcode-Organizer&quot;&gt;Symbolication via Xcode Organizer&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;于是我又去issues里面看了看，虽然没解决我的问题，但也有其他的收获，找到了一个叫objc 的logging framework,叫&lt;a href=&quot;https://github.com/robbiehanson/CocoaLumberjack&quot;&gt;CocoaLumberjack&lt;/a&gt;，支持&lt;a href=&quot;https://github.com/robbiehanson/CocoaLumberjack/wiki/XcodeColors&quot;&gt;xcodeColors&lt;/a&gt;，用起来很简单，也很灵活。可以根据Loglevel来进行过滤，这样开发的时候控制台中我们需要的信息就清晰多了。&lt;/p&gt;

&lt;p&gt;——-分割线—–&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.taofengping.com/2013/03/28/crash_again/&quot;&gt;解决&lt;/a&gt;remote symbolicatecrash的问题&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>cocos2d中实现黑白动画（RGB-> Grayscale）</title>
   <link href="http://blog.inico.me/2012/11/28/cocos2d_rgb_gray_animation"/>
   <updated>2012-11-28T23:24:50+00:00</updated>
   <id>http://blog.inico.me/2012/11/28/cocos2d_rgb_gray_animation</id>
   <content type="html">&lt;p&gt;在做Hero项目战斗模块的时候碰到一个需求，说要实现一个Sprite动画，效果是从全彩慢慢变到黑白（灰度图）。刚开始以为用TintTo就能解决了，用了一下之后发现其实Tint其实是一个着色的过程，并不能达到自己要的效果。&lt;/p&gt;

&lt;p&gt;回头想了想，感觉好像这个效果做起来还有点麻烦，因为首先我们Sprite的纹理位图，有RGBA四个通道。但是灰度图是单通道的，蛋疼····没办法，还是得求助google大神，然后看到在&lt;a href=&quot;http://en.wikipedia.org/wiki/Grayscale&quot;&gt;wiki上关于灰度图的说明&lt;/a&gt;，里面有一章提到了converting RGB to grayscale，文章大致浏览了一下，关键用到了这个公式&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://upload.wikimedia.org/math/0/d/9/0d94a32c1f2f53a4ce8cb2cd564b6627.png&quot; alt=&quot;Y' =  0.299 R + 0.587 G + 0.114 B&quot; /&gt;&lt;/p&gt;

&lt;p&gt;自己在UIKit里随便找了一张图试了一下，果然，把每个像素的RBG值进行换算后得到的Y后进行赋值，得到了一张看似灰度的rgb图。&lt;/p&gt;

&lt;p&gt;接下来的事情相对就好办了，要得到动画的话我们只要在RGB-&amp;gt;finalRGB之间做差值运算就可以了。只要得到CCSprite在openGL里的纹理信息，然后动态改变它就能打到我要的效果了。&lt;/p&gt;

&lt;p&gt;废话说完。写了一个&lt;a href=&quot;https://github.com/demon1105/TextureMotify&quot;&gt;demo&lt;/a&gt;，已上传·&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>UIScrollView做无尽循环滚动</title>
   <link href="http://blog.inico.me/2012/11/19/uiscrollview_inifiti_animatio"/>
   <updated>2012-11-19T15:46:37+00:00</updated>
   <id>http://blog.inico.me/2012/11/19/uiscrollview_inifiti_animatio</id>
   <content type="html">&lt;p&gt;今天接到一个需求，首先要做几个UITableView页，然后实现在tableView页上作水平滚动进行翻页，并且可以做无尽的循环滚动。（—-3,1,2,3,1—-，类似这样走马灯的效果）&lt;/p&gt;

&lt;p&gt;首先分解了一下的：&lt;/p&gt;

&lt;p&gt;1、要实现水平滚动可以简单通过scrollView来实现，简单地就是设置其contentSize为我们子页面的总宽度，然pagingEnabled为yes，当滚动到下一个子页面的时候就会进行判断是否翻页。&lt;/p&gt;

&lt;p&gt;2、无尽循环的话借用&lt;a href=&quot;http://stackoverflow.com/questions/2735804/objective-c-endless-uiscrollview-without-pagingenabled&quot;&gt;StackOverFlow&lt;/a&gt;上的一个思路，在首页index=0前面再加上一页，内容刚好是我们尾页的内容。在尾页最后刚好加上一页，内容刚好是首页的内容。最后滑动到首页或者尾页的时候，做一个伪处理:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_tv_scrollView&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;scrollRectToVisible&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;animated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;关于第二点，找到了一篇&lt;a href=&quot;http://furnacedigital.blogspot.fr/2011/04/uiscrollview.html&quot;&gt;中文的&lt;/a&gt;，讲得还比较详细。&lt;/p&gt;

&lt;p&gt;写了一个&lt;a href=&quot;https://github.com/demon1105/scroll-List&quot;&gt;demo&lt;/a&gt;,已上传~&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>TexturePacker纹理图对UIImage的支持</title>
   <link href="http://blog.inico.me/2012/11/08/texturepacker_for_uiimage"/>
   <updated>2012-11-08T21:01:01+00:00</updated>
   <id>http://blog.inico.me/2012/11/08/texturepacker_for_uiimage</id>
   <content type="html">&lt;p&gt;之前在做HEROX项目的时候，想到过一个问题。项目如果是cocos2d+UIKit混合的模式，碰到一些图片如果要共用的话就会有点麻烦。因为Cocos2d一般会用textruePacker或者其他一些软件将一些资源图进行打包，合并到一张图上，而且在这个过程中有可能会对图片进行旋转和切边(trim)，如果单纯试用UIImage的切图方法是不行的。这些天晚上回去抽空写了一个方法可以先对TexturePacker中发布出的材质图进行重新解析，然后还原成我们需要的原图，统一放到内存中。要用的时候根据原图的名字进行读取就行了。&lt;/p&gt;

&lt;p&gt;项目里面还有点小问题，在TextureManager中有比较详细的注释，因为对CoreGraphics框架不是非常熟悉，一时也没找到原因。项目先传到&lt;a href=&quot;https://github.com/demon1105/TextureCocoa&quot;&gt;github&lt;/a&gt;上。&lt;/p&gt;

&lt;p&gt;但是目前有个内存方面的小问题（没有内存泄露，但运行的时候控制台会输出对象释放提前什么的警告：incorrect checksum for freed object - object was probably modified after being freed），我这里只是为了实现功能去做这个模块，效率方面暂时也没有考虑，之后有时间再去修改完善。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>CGDataProviderCreateWithData对内存数据的释放</title>
   <link href="http://blog.inico.me/2012/11/04/cgdataprovidercreatewithdata_memory_release"/>
   <updated>2012-11-04T14:42:04+00:00</updated>
   <id>http://blog.inico.me/2012/11/04/cgdataprovidercreatewithdata_memory_release</id>
   <content type="html">&lt;p&gt;这几天在搞个东西，想对TexturePacker生成的图片和plist进行还原，网上找了个一些朋友的方法，大致的思路基本上就是使用UIImage，然后通过读取.plist文件中的数据，解析之后对原图进行clip操作，这样做的话如果之前Publish出来的texture图是经过了优化处理的(trim，如果在texturePacker中勾选了这个选项，对Publish出来之后图进行仔细比较后应该不难发现，如果原图的有效像素点周围存在大片的R=0,G=0,B=0A=0的区域，texturePacker导出时会对这些区域进行优化，认为这些区域是没有意义的并切除，具体可以对看plist文件中source字段的信息进行比较)，那我们得到的UIImage将不是和原图完全一样的。&lt;/p&gt;

&lt;p&gt;我要做的工作就是先在内存中先绘制一片和原图一样大小的区域(sourceSize)，然后得到纹理(texture)图中一小块切图区域的内存信息(frame)，最后通过sourceColorRect和offset对数据进行还原，将frame绘制到sourceSize中正确的位置，使它和原图的信息保持一致。&lt;/p&gt;

&lt;p&gt;在最后绘制CGImageRef的时候我用到了&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;    
    &lt;span class=&quot;cm&quot;&gt;/* Create an image. */&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;CG_EXTERN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGImageRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGImageCreate&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    	&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitsPerComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitsPerPixel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytesPerRow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;CGColorSpaceRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;space&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;CGBitmapInfo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bitmapInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;CGDataProviderRef&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGFloat&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldInterpolate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;CGColorRenderingIntent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intent&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;这个方法，在这里传递图像的信息是通过provider这个参数传入的，要得到这个对象我们则需要通过如下的方法创建：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/* Create a direct-access data provider using `data`, an array of `size`
bytes. `releaseData` is called when the data provider is freed, and is
passed `info` as its first argument. */&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;CG_EXTERN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CGDataProviderRef&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CGDataProviderCreateWithData&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
	&lt;span class=&quot;n&quot;&gt;CGDataProviderReleaseDataCallback&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;releaseData&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;在这个构建方法中我们可以将数据(data)作为第二个参数传入，具体各个参数的含义可以看注释&lt;/p&gt;

&lt;p&gt;创建CGDataProviderRef对象后有个问题我们需要注意的是，当我们使用完该对象需要对这个对象进行释放，当然我们malloc出来的数据区域也要进行free，释放CGDataProviderRef对象我们需要用到CGDataProviderRelease，而我们的data却不能在此时立即free掉，否则就会看到创建出的图片在绘制的屏幕上之后数据不对，出现花屏的情况。在这里我推断有可能iOS在绘制UIImage的时候使用的内存信息只是作了一个简单的引用指向，所以我们立即释放data的话就会造成数据错误。&lt;/p&gt;

&lt;p&gt;如果仔细看CGDataProviderCreateWithData方法的注释，应该就能明白，正确的做法应该是实现自己的释放方法，然后将该方法作为CGDataProviderCreateWithData的最后一个参数进行传入，那么CGDataProviderRef释放的时候就会对该CGDataProviderReleaseDataCallback进行回调，在里面我们可以安全释放我们的图像数据。&lt;/p&gt;

&lt;p&gt;CGDataProviderReleaseDataCallback的写法可以参考下面的格式，具体的实现应该根据需求的不同而不同:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;providerReleaseData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
 </entry>
 
 <entry>
   <title>自动导出objc-c的Model</title>
   <link href="http://blog.inico.me/2012/11/01/auto_create_objc-c_model"/>
   <updated>2012-11-01T22:53:28+00:00</updated>
   <id>http://blog.inico.me/2012/11/01/auto_create_objc-c_model</id>
   <content type="html">&lt;p&gt;接上&lt;a href=&quot;http://demon1105.gotoip4.com/2012/10/29/cocoapods/&quot;&gt;前几天提到的&lt;/a&gt;，在开发的时候经常碰到一些重复性的劳动，比如说服务器返回的都是统一的json的格式，客户端根据key进行解析，然后创建Model,设置各个字段，写parse方法…(此处省略几百字)。&lt;/p&gt;

&lt;p&gt;一两个Model的话应该还好，数量一多的话就很麻烦了，尤其是当Model的字段很多的时候。这里我写了一个&lt;a href=&quot;https://github.com/demon1105/AutoCreateModelScript&quot;&gt;python的脚本&lt;/a&gt;，用法很简单，只要按照demo里面在plist里设置相对的一些参数，就能根据预置的参数生成Model.h和Model.m文件，文件的名字还有类名都是用户自己定义的。当然还有一些不足的地方，github上的wiki也写得不是很清楚，准备等版本再完善以后逐渐补充起来。目前为止基本的一些需求应该完全可以满足了。python写得很烂，因为第一次写，就当练习基本语法了···&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>.bash_profile和bashrc的区别</title>
   <link href="http://blog.inico.me/2012/10/31/bash_profilebashrc"/>
   <updated>2012-10-31T13:05:32+00:00</updated>
   <id>http://blog.inico.me/2012/10/31/bash_profilebashrc</id>
   <content type="html">&lt;p&gt;今天写了一个xcode打包后自动上传ipa到svn服务器的脚本，一下子感觉自动化+命令行才是王道。于是想平时的一些操作用图形化的界面虽然看上去人性化了，是不是有点过于繁琐，那就试试简洁的。&lt;/p&gt;

&lt;p&gt;首先我想把本地的一个字典程序换成command line的，google了一下有个朋友已经写好了一个&lt;a href=&quot;http://code.google.com/p/chinese-dictionary/wiki/install&quot;&gt;基于php的程序&lt;/a&gt;，这里我按照他的步骤安装了一下，发现在命令行里面输入dict的时候提示command not found.我猜测应该是.bashrc没有加载的缘故，之前只用过.bash_profile来设置一些环境变量，而.bashrc是我刚刚vi新建的。&lt;/p&gt;

&lt;p&gt;于是继续google,查询了一下&lt;a href=&quot;http://linux.chinaunix.net/doc/system/2005-02-03/1084.shtml&quot;&gt;bash_profile和bashrc的一些区别&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;* &amp;lt;~/.bash_profile&amp;gt;每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件**仅仅执行一次**!默认情况下,他设置一些环境变量,执行用户的.bashrc文件.
* &amp;lt;~/.bashrc&amp;gt;该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取
* &amp;lt;~/.bash_logout&amp;gt;当每次退出系统(退出bash shell)时,执行该文件.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;于是我尝试command+n一个新的Terminal，还是没有加载dict命令,然后我又找到了&lt;a href=&quot;http://coder.aqualuna.me/2012/03/bashrc-in-mac-terminal-os-x-lion.html&quot;&gt;这篇文章&lt;/a&gt;，其中引用到一段话:&lt;/p&gt;

&lt;blockquote&gt;

  &lt;h3 id=&quot;mac-os-x--an-exception&quot;&gt;&lt;a href=&quot;http://www.joshstaiger.org/archives/2005/07/bash_profile_vs.html&quot;&gt;Mac OS X — an exception&lt;/a&gt;&lt;/h3&gt;

  &lt;p&gt;&lt;a href=&quot;http://www.joshstaiger.org/archives/2005/07/bash_profile_vs.html&quot;&gt;An exception to the terminal window guidelines is Mac OS X’s Terminal.app, which runs a login shell by default for each new terminal window, calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bash_profile&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bashrc&lt;/code&gt;. Other GUI terminal emulators may do the same, but most tend not to.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;也就是说在mac是一朵奇葩，他每次都会重新加载.bash_profile中的设置，默认的时候并不会加载.bashrc，按照文章中说的，我在.bash_profile中加了一个判断:&lt;/p&gt;

&lt;blockquote&gt;

  &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if [ -f ~/.bashrc ]; then
   source ~/.bashrc
fi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/blockquote&gt;

&lt;p&gt;最后重新command+n一个新的Terminal,搞定～&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>CocoaPods</title>
   <link href="http://blog.inico.me/2012/10/29/cocoapods"/>
   <updated>2012-10-29T22:18:15+00:00</updated>
   <id>http://blog.inico.me/2012/10/29/cocoapods</id>
   <content type="html">&lt;p&gt;今天快下班的时候和同事闲聊，说写model是一件很痛苦的事情，服务器返回的都是JSON的格式，客户端在解析的时候无非是根据key来得到相应的value。于是捉摸着可以写一个程序，&lt;a href=&quot;http://demon1105.gotoip4.com/2012/11/01/auto_create_objc-c_model/&quot;&gt;简单配置一下之后，可以自动生成头文件和实现文件&lt;/a&gt;，讨论到后来觉得这个方案可行，考虑到跨平台的问题，准备着手用python来写，找了一下python刚好有一个Model叫plistlib可以直接读取plist中的数据，想想应该很快就能实现大致的功能。&lt;/p&gt;

&lt;p&gt;python虽然接触过一段时间，但是从来没实际操作过，于是先在google上查点资料。查着查着，也不知道怎么查到了&lt;a href=&quot;http://cocoapods.org/&quot;&gt;cocoaPods&lt;/a&gt;的git，看了下介绍感觉也蛮有意思的，查了下，原来是一个比较著名的在cocoa下面的项目包管理器。晚上回来之后就在自己的mac上装了一下，感觉还不错。&lt;/p&gt;

&lt;p&gt;有了这东西，我们在开发的时候如果碰到项目中添加了什么第三方的库（比如经常用到的JSONKit,AFNetworing等等），就不需要杂七杂八一堆往项目里面拖入了。只要按照documents里面说明的设置Podfile之后,pod install，整个世界清净了···&lt;/p&gt;

&lt;p&gt;至于文章开头的自动model工具，早被我抛到九霄云外了···今天没时间了，以后写好再补上。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>objc的arc配置</title>
   <link href="http://blog.inico.me/2012/10/27/objcarc"/>
   <updated>2012-10-27T15:44:44+00:00</updated>
   <id>http://blog.inico.me/2012/10/27/objcarc</id>
   <content type="html">&lt;p&gt;xcode好像升级到4.3之后就多了个&lt;a href=&quot;http://clang.llvm.org/docs/AutomaticReferenceCounting.html&quot;&gt;ARC&lt;/a&gt;的选项，如果勾选这个属性的话，编译器编译的时候就会根据对象的一些属性(strong,weak等)设置，对.m文件中需要ARC的对象进行自引用计数，这样的话一方面来说降低了objc的学习门槛，但是如果同一个项目里面既有ARC写的.m又有非ARC的，那就需要对项目中具体的实现文件进行编译设置。&lt;/p&gt;

&lt;p&gt;因为之前做的项目都不是基于ARC的，所以刚开始也没有关注这一点，后来在github上看到一些有意思的开源的库基于ARC的，所以查了一下设置，在这里做一个记录:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;如果你的project是基于ARC的，那么在target的building pharses里面需要对非ARC的文件设置为:-fno-objc-arc，反之，如果project是不基于ARC的，就需要对ARC的文件设置:-f-objc-arc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/blockquote&gt;

</content>
 </entry>
 
 <entry>
   <title>cocos2d的一些动画编辑器</title>
   <link href="http://blog.inico.me/2012/10/26/animation_editor"/>
   <updated>2012-10-26T23:59:38+00:00</updated>
   <id>http://blog.inico.me/2012/10/26/animation_editor</id>
   <content type="html">&lt;p&gt;大概三四个月前，发现一款很赞的游戏&amp;lt;&lt;a href=&quot;https://itunes.apple.com/us/app/hero-academy/id488156323?mt=8&quot;&gt;HeroAcademy&lt;/a&gt;&amp;gt;,玩了一下感觉游戏中人物的动画做得很不错，游戏中Sprite的动画都显得很和谐，也很流畅。下载Ipa之后解包看了下，果然和想的一样，精灵的身体各个部位都拆解开放在了一张纹理图上，同时看到了一些扩展名为.animation的文件，直接用文本编辑器打开看了下，其实就是一些html标签组织的信息，看过texturePacker发布后的.plish文件的应该马上能想到，其实这些.animation文件是通过某种2d骨骼动画编辑器经过美工调整后直接导出的文件，解析帧动画的时候只要在动画frame里面找到sprite各个part在texture中的坐标然后组织，就形成一个完整的帧画面。依次解析所有的frame之后自然形成了一个比较流畅的动画。&lt;/p&gt;

&lt;p&gt;这样做的好处显而易见，美工那边不需要重复绘制一个sprite帧动画中相同的部分，只要将sprite拆解开之后重新组织，很多动画就可以灵活地做出来了，之后导出.animation就行了，工作量大大降低，而且图片文件不会那么多，客户端在开发的时候也不会因为内存的问题太过于头疼。其实这种模式在J2me的时代早就被采用了，我这里只是炒了次冷饭。&lt;/p&gt;

&lt;p&gt;之后公司里也有声音说接下来开发的游戏可能会考虑使用类似的动作编辑器，让我找找看有没有比较易用的。于是本人就开始寻找了，终于在cocoaChina的论坛上找到过一哥们儿推荐的，叫&lt;a href=&quot;http://www.motionwelder.com/&quot;&gt;MotionWelder&lt;/a&gt;,原帖在&lt;a href=&quot;http://www.cocoachina.com/bbs/read.php?tid=80815&quot;&gt;这里&lt;/a&gt;，总得来说这个软件还是不错的，有java的版，有支持cocos2d的库，做动画的时候不用考虑OS了。不过有几个缺点：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 不能单独调整某一个小切图的色彩，也就是说如果同一张拼图，你想做成A(我方，红色调)，B（敌方，蓝色调），这个是没法做到的。
2. 不支持retina，至少在我之前用的时候是不支持的。不过只要看过CCMWSprite后，稍稍修改- (void) setFrameIndex:(int) index的几个地方就可以实现支持两种屏幕
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;但是后来公司在开发的时候居然还是选择了让美工逐帧去绘制，我除了无语还能说什么呢，当然这就是后话了。&lt;/p&gt;

&lt;p&gt;刚好前段时间又在微博上看到&lt;a href=&quot;http://cocosbuilder.com/&quot;&gt;cocosBuilder&lt;/a&gt;又发了新的版本，之前的1.0我用过，在搭建静态的界面，做得的确可圈可点，除了一些操作上的不便利之外，没有什么太大的Bug,但是不足的是不支持动画编辑。但是在2.0上cocosBuilder添加了这个功能，并且支持骨骼动画编辑，于是我就抱着试试的态度装了2.0。&lt;/p&gt;

&lt;p&gt;总得来说2.o在1.0的基础上做了比较大的改变，首先组建的创建更加人性化了，在右上角直接有对应的button可以操作，而且在工程的结构组织上和1.0相比，1.0就像是个简易版，2.0的话就是企业版了。首先2.0在创建的时候并不是直接创建.ccb，对应的还包括.proj项目文件，在项目中你可以统一管理多个.ccb场景。并且在工程发布的时候可以生成.ccbi,取代了在cocos2d中使用的ccb文件，这样操作当然让你的项目更加的安全了。说了这么多还没讲到动画编辑功能，直入正题：&lt;/p&gt;

&lt;p&gt;个人感觉CocosBuilder在动画的编辑操作设计上应该借鉴了Adobe的影视剪辑和后期处理软件，当然这只是我的猜测。因为在CocosBuilder的时间线操作区域设计得和premiere设计得非常像，因为本人之前做过一些操作过这些软件，所以在使用CococsBuilder2.0进行一些动画的创建和编辑的时候显得非常顺手，类似一些添加关键帧的快捷键等等，在我印象中和AE中的快捷键都是一样的。到目前为止感觉都还是挺不错的。&lt;/p&gt;

&lt;p&gt;但是在做骨骼动画的时候就觉得不是很顺手了。因为没有一个窗口可以预览所有.plist文件中的图片，仅仅靠图片名来选切片操作和MotionWelder比起来就显得不是很人性化了。但是在CococsBuilder里面你可以分门别类地在任意的关键帧里面设置任意切面的属性，包括颜色旋转缩放等等。&lt;/p&gt;

&lt;p&gt;说到最后，希望CococsBuilder可以对动画编辑这块做一些强化，因为是开源的，有空也可以去github上学习一下，说不定自己哪天兴趣来了做一个动画编辑加强的插件也蛮好的·&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>iOS 6.0之后的屏幕问题</title>
   <link href="http://blog.inico.me/2012/10/22/ios_6_0_screen_undefine"/>
   <updated>2012-10-22T22:36:08+00:00</updated>
   <id>http://blog.inico.me/2012/10/22/ios_6_0_screen_undefine</id>
   <content type="html">&lt;p&gt;之前iOS6.0发布后天真地认为siri支持所有设备，于是手贱了把自己ipad升了个级。之后却发现没有siri，差点把home键都给按爆了。悲剧的是因为IDE没有升级所以也没法调试了，只能用模拟器。用过appstore在线下载xcode的朋友应该体会过那种速度，在这里我只能为具有中国特色的网络再次感到惊叹。&lt;/p&gt;

&lt;p&gt;装了xcode4.5.1以后运行之前的程序发现控制台会输出一句缺少xxx图片，应该是为了支持iphone5而设置的默认背景图，还有一句:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Application windows are expected to have a root view controller at the end of application launch. 大致是说程序的窗口对象应该在程序加载结束前设置一个根控制器对象。进入程序后发现原来在iOS6.0里苹果把屏幕的旋转事件传递机制修改过了。以前可以直接在window上面添加一个view,现在的如果要想得到旋转事件的话就必须通过rootController,在window中设置跟控制器为rootController之后事件才会传递到rootController里面。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;说到这里，以为问题都解决了。于是运行了一个cocos2d的程序，结果发现还是有类似的旋转问题。网上一搜发现已经有很多人抛出了问题的解决方案：&lt;/p&gt;

&lt;p&gt;首先还是和之前说的一样，需要在&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UIApplication&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;application&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;didFinishLaunchingWithOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSDictionary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;launchOptions&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;内设置根控制器对象，在这里我们可以根据自己的需要添加一下判断之后再进行处理，然后我们需要在RootViewController方法中根据需要实现另外两个委托方法&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-objc&quot; data-lang=&quot;objc&quot;&gt;    
&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NSUInteger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;supportedInterfaceOrientations&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UIInterfaceOrientationMaskLandscape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BOOL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shouldAutorotate&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;YES&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;这里我看了一下，貌似之前的几个委托方法在6.0里面已经被放入到弃用的分类里了&lt;/p&gt;
&lt;blockquote&gt;

  &lt;p&gt;网上大部分的朋友解决方案到此就结束了，但是我的问题还是依旧。后来看了下发现原来程序target的summry一直都没有设置support interface orientations,设置了支持两种landscape模式之后，cmd+R.搞定·&lt;/p&gt;
&lt;/blockquote&gt;
</content>
 </entry>
 
 <entry>
   <title>HockeyKit</title>
   <link href="http://blog.inico.me/2012/10/21/hockeykit"/>
   <updated>2012-10-21T22:31:24+00:00</updated>
   <id>http://blog.inico.me/2012/10/21/hockeykit</id>
   <content type="html">&lt;p&gt;在不知道&lt;a href=&quot;https://testflightapp.com/&quot;&gt;TestFight&lt;/a&gt;之前，傻逼地认为ipa交给测试之后，只能通过itunes同步进行安装（包括破解后用的第三方工具安装）。后来发现这个好东西之后其实也没怎么用得上，因为公司的网速实在不怎么样，每次打包好之后的ipa包大概也有50M+,上传到TestFight服务器上测试进行OTA安装又要重新下载，感觉实在有点费时间，google了之后发现其实还有&lt;a href=&quot;https://github.com/TheRealKerni/HockeyKit/&quot;&gt;HockeyKit&lt;/a&gt;这样的好东西。&lt;/p&gt;

&lt;p&gt;简单地搭建一个支持php的服务器就能安装Hockey的服务端，假设在公司或者小团队的内部网络中，开发编译打包后上传就不是问题了，测试的安装也可以一气呵成。 lion中自带了apache，打开httpd.conf之后修改一下配置，让apache支持php就可以了。&lt;/p&gt;

&lt;p&gt;下面简单记录一下HockeyKit Server的搭建过程，英文好的可以参考HotkeyKit在Github上的&lt;a href=&quot;https://github.com/TheRealKerni/HockeyKit/wiki/Server&quot;&gt;wiki&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. git clone https://github.com/TheRealKerni/HockeyKit.git，打开包之后会发现包内包含server，client，还有demo。这里我们只要server
2. 然后我们要有一个支持php5的服务器，确保你的服务器的httpd.conf 中 _AllowOverride All_ ，以支持HockeyKit Server中子目录的配置重载，确保服务的rewirte可用（lion默认开启 LoadModule rewrite_module libexec/apache2/mod_rewrite.so)
3. 在服务器相应的位置创建一个子目录，在这里我们把这个目录作为 HockeyKit的公共服务目录,我们假设这个目录叫做_public_
4. cd hockeykit/server/php/public ls .
发现包含隐藏的.htaccess，将包内所有的文件都cp到我们在上一步创建的_public_中
5. 在服务目录下创建另一个子目录，出于安全考虑，我们把这个目录放在_public_的外部，可以和_public_处于同一层级，我们可以把这个目录命名为_include_，用于存放一些HockeyKit服务用到的一些库文件
6. 打开我们刚刚cp到_public_包内的config.php文件,修改_include_相对与_public_路径
7. 修改权限，使php对_public_中的stats目录拥有写权限
8. 打开stats目录下的.htaccess文件可以针对当前目录的访问权限等进行适当配置
9. 在我们上文中的_public_目录下创建你的应用子目录，用APP的bundle name进行命名，以便区分
10. 将hockeykit/server/php/public/test中所有的目录copy到我们在服务器下的创建的public中
11. 在设备中访问xxx.xxx.xxx.x/xxx/public，应该能看到一个基本的界面了，里面包含了我们在上一步中放入public中的一些iOS的应用（如果是android设备的话看到的应该是一些android的应用）
12. 点击install application，如果出现alertview提示错误，重新回到步骤2检查一下是否设置了_AllowOverride All
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 
</feed>
