<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Push on Chen</title><link>https://hechen.github.io/zh-cn/tags/push/</link><description>Recent content in Push on Chen</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 21 Dec 2018 14:30:50 +0000</lastBuildDate><atom:link href="https://hechen.github.io/zh-cn/tags/push/index.xml" rel="self" type="application/rss+xml"/><item><title>UserDefaults and Keychain</title><link>https://hechen.github.io/zh-cn/post/userdefaults-and-keychain/</link><pubDate>Fri, 21 Dec 2018 14:30:50 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/userdefaults-and-keychain/</guid><description>&lt;p&gt;Apple 提供了几种持久化方案，其中 UserDefaults 和 Keychain 是 App 开发过程中使用频率最高的方案，而且从以往和同事的探讨过程中发现对这两个概念中有一些细节还是理解不太透彻，因此本文会针对这二者展开讲一讲。&lt;/p&gt;
&lt;h2 id="userdefaults"&gt;UserDefaults&lt;/h2&gt;
&lt;p&gt;首先，阅读完 Apple 关于 UserDefaults 一节的文档描述之后，我觉得有两个需要注意的点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;UserDefaults 的构成&lt;/li&gt;
&lt;li&gt;UserDefaults 的目的&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="userdefaults-构成"&gt;UserDefaults 构成&lt;/h3&gt;
&lt;p&gt;我们可以看看具体 UserDefaults 存储的地方，如下图，我们在应用中写入 Demo 数据：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Write Key-Value to UserDefaults" loading="lazy" src="https://i.imgur.com/wq9onOa.png"&gt;&lt;/p&gt;
&lt;p&gt;打印 Library 路径，在 Finder 中打开路径:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Library" loading="lazy" src="https://i.imgur.com/65ybYX6.png"&gt;&lt;/p&gt;
&lt;p&gt;如下展示内容，可以看到在 Preferences 目录中存在某个文件，例如该 App Library 目录下存放的文件为 &lt;code&gt;app.chen.ios.PersistenceDemo.plist&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cache" loading="lazy" src="https://i.imgur.com/ChqnDJa.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Preferences" loading="lazy" src="https://i.imgur.com/cPvlFdR.png"&gt;&lt;/p&gt;
&lt;p&gt;该 plist 内容如图所示，即为我们之前在 App 中写入的 Key-Value。&lt;/p&gt;
&lt;p&gt;&lt;img alt="plist" loading="lazy" src="https://i.imgur.com/shdXoZN.png"&gt;&lt;/p&gt;
&lt;p&gt;所以这也证明了，我们针对 UserDefaults 的读写实质上是针对 plist 文件的读写。&lt;/p&gt;
&lt;p&gt;iOS 系统会自动帮你做 &lt;code&gt;plist&lt;/code&gt; 文件的读入以及 Cache，根据情况会把你在内存中所做的操作同步到 &lt;code&gt;plist&lt;/code&gt; 文件（UserDefaults 同步到内存是同步的，同步到 Database 是异步的， iOS 8 开始，会有一个常驻进程 &lt;code&gt;cfprefsd&lt;/code&gt; 来负责同步）。&lt;/p&gt;</description></item><item><title>In App Purchase</title><link>https://hechen.github.io/zh-cn/post/in-app-purchase/</link><pubDate>Thu, 24 May 2018 10:40:39 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/in-app-purchase/</guid><description>&lt;p&gt;对于在 App Store 中上架的应⽤来说，应⽤内购买(In-App Purchase，简称 IAP) 应该是一个避不开的话题，尤其是去年微信打赏和 Apple 之间的争执更让 IAP 火了一把，不仅仅大公司，作为个人开发者来讲，IAP 也是非常重要的，说不定就是你养家糊口的工具呢。&lt;/p&gt;
&lt;p&gt;整个 IAP 的过程，在客户端的实现依赖于 &lt;code&gt;StoreKit&lt;/code&gt; 这个框架，所有的支付相关操作都是交由 StoreKit 来完成的。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://i.imgur.com/EkBwhM4.png"&gt;&lt;/p&gt;
&lt;p&gt;首先，我们先复习一下 IAP 的整个流程。&lt;/p&gt;
&lt;h2 id="in-app-purchase-的整体流程"&gt;In App Purchase 的整体流程&lt;/h2&gt;
&lt;h3 id="阶段-1"&gt;阶段 1&lt;/h3&gt;
&lt;p&gt;&lt;img alt="In App Purchase 过程" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/2018-09-03-4DDE8387-EDB1-42CC-B18C-3DC6CA1DC688.png"&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;加载 In-App Identifier&lt;/li&gt;
&lt;li&gt;客户端从 AppStore 中获取本地化的商品信息。&lt;/li&gt;
&lt;li&gt;把 IAP 的购买界⾯面展示给⽤用户，⽤用户可以同意购买并点击购买按钮。&lt;/li&gt;
&lt;li&gt;⽤用户授权购买，客户端向服务器器发送购买请求。&lt;/li&gt;
&lt;li&gt;服务器器处理理购买请求，并把结果返回给 &lt;code&gt;StoreKit&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果购买请求验证通过，客户端此时解锁内容或者提供金币。&lt;/li&gt;
&lt;li&gt;至此，整个交易易流程结束。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="阶段-2"&gt;阶段 2&lt;/h3&gt;
&lt;p&gt;具体到和 Apple Store 打交道的话，如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="IAP With App Store" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/2018-08-27-intro_2x.png"&gt;&lt;/p&gt;
&lt;h3 id="阶段-3"&gt;阶段 3&lt;/h3&gt;
&lt;p&gt;如果涉及到自己 App 端 Server 的参与，基本如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="IAP With Business Server" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/2018-08-29-1*MwLeHUGSupbb9j-oYQyflw.png"&gt;&lt;/p&gt;
&lt;p&gt;正常多出的几步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;获取 Product 标识列表；&lt;/li&gt;
&lt;li&gt;客户端上传 Receipt 数据给 Server，Server 自行校验或者使用 Apple 的接口校验；&lt;/li&gt;
&lt;li&gt;Server 端告知给客户端付费内容&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="注册商品"&gt;注册商品&lt;/h3&gt;
&lt;p&gt;商品注册是通过 iTunes Connect 后台进行的，其中商品类型需要提前明确好。&lt;/p&gt;</description></item><item><title>理解响应者和响应链</title><link>https://hechen.github.io/zh-cn/post/understanding-responders-and-the-responder-chain/</link><pubDate>Mon, 13 Nov 2017 21:22:44 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/understanding-responders-and-the-responder-chain/</guid><description>&lt;p&gt;Apps 是通过响应者（responder）对象来接收和处理事件的。一个响应者对象是 UIResponder 类的一个实例，我们常见的 UIView，UIViewController 以及 UIApplication 都是 UIResponder 的子类。 UIKit 自动帮你管理着这些 responder 相关的行为，包括事件是如何从一个 responder 传递给另一个 responder 的等等。当然，你也可以修改你的 app 中事件传递的默认行为。&lt;/p&gt;
&lt;p&gt;UIKit 会把大部分的事件都传递给最适合的 responder 对象来处理。如果该 responder 无法处理该事件，UIKit 就会继续把该事件沿着当前的响应者链传递到下一个 responder。响应者链就是你的 App 中所有响应者的动态配置，也因为其是动态的，你的 App 中不可能只存在单一的响应者链。由于事件总是从特定的响应者那里流转到更通用的响应者那里，因此很容易确定某响应者链中下一个响应者是谁。举个例子，一个 view 的下一个响应者是其 superview 或者负责管理它的 view controller。事件就是这样在响应者链中传递直到其被处理掉。&lt;/p&gt;
&lt;p&gt;下图展示了一个界面中包含了 一个 Label，一个 TextField，一个 Button 以及两个容器 view 的 App 中响应链是什么样子的。如果 TextField 不处理某个事件，UIKit 就会把该事件发送给 TextField 的父级 UIView 对象，同样的，如果该对象依然处理不了，就会传递给该 view 对象的 window。如果 window 对象也依然无法处理该事件，UIKit 最终会把该事件传递给 UIApplication 对象，一般上该 UIApplication 对象是 App 的 delegate 对象并且是 UIResponder 实例，当然这个时候已经脱离了响应者链了。&lt;/p&gt;</description></item><item><title>@autoclosure &amp;&amp; @escape</title><link>https://hechen.github.io/zh-cn/post/autoclosure-escape/</link><pubDate>Sun, 12 Nov 2017 20:01:54 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/autoclosure-escape/</guid><description>&lt;p&gt;我们知道在 &lt;code&gt;swift&lt;/code&gt; 中，闭包（closure）是一等公民，因此可以被当作参数传递，在学习 swift 的过程中经常会看到某些关键字修饰该闭包，&lt;code&gt;@autoclosure&lt;/code&gt;， &lt;code&gt;@escape&lt;/code&gt; 就是其中比较常见的两种关键字。&lt;/p&gt;
&lt;h3 id="escape-和-nonescape"&gt;@escape 和 @nonescape&lt;/h3&gt;
&lt;p&gt;当一个闭包被当作参数传递给一个函数，但是当该函数内容执行完毕返回之后，该闭包才会被执行，我们就称该闭包要 escape 某个函数，那 &lt;code&gt;@escape&lt;/code&gt; 关键字就是用来表示该闭包是允许在函数返回之后被调用的。&lt;/p&gt;
&lt;p&gt;我们用 swift 官方文档的例子来看，如下所示&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;completionHandlers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;someFunctionWithEscapingClosure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;escaping&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;completionHandlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;someFunctionWithEscapingClosure(_:)&lt;/code&gt; 的参数是一个闭包，函数内部会把传入的闭包存到之前声明的数组里以便之后进行调用，可以看到，在函数参数的声明部分添加了 &lt;code&gt;@escaping&lt;/code&gt; 关键字，如果这里不添加的话，就会在编译的时候报错：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;error: passing non-escaping parameter &lt;span class="s1"&gt;&amp;#39;completionHandler&amp;#39;&lt;/span&gt; to &lt;span class="k"&gt;function&lt;/span&gt; expecting an @escaping closure
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; completionHandlers.append&lt;span class="o"&gt;(&lt;/span&gt;completionHandler&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;针对标记了 @escaping 关键字含义代表你必须在该闭包内部显式的使用 self 关键字，官方文档中又列举了另外一个例子，如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;someFunctionWithNonescapingClosure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;closure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;someFunctionWithEscapingClosure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;someFunctionWithNonescapingClosure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SomeClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Prints &amp;#34;200&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;completionHandlers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;first&lt;/span&gt;&lt;span class="p"&gt;?()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Prints &amp;#34;100”&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;someFunctionWithEscapingClosure(_:)&lt;/code&gt; 是一个可逃逸的闭包，意味着你需要显示的调用 self 关键字， 而 &lt;code&gt;someFunctionWithNonescapingClosure(_:)&lt;/code&gt; 是非逃逸的闭包，意味着你可以隐式的调用 self。&lt;/p&gt;</description></item><item><title>关于 iOS10 Notification 的那些事儿</title><link>https://hechen.github.io/zh-cn/post/ios-notification/</link><pubDate>Sat, 20 May 2017 10:10:54 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/ios-notification/</guid><description>&lt;h2 id="概览"&gt;概览&lt;/h2&gt;
&lt;p&gt;推送通知我们大家都不陌生，可以说几乎每个使用智能手机的人每天都会被不同的通知 &lt;em&gt;打扰&lt;/em&gt; 到，正式因为合适的推送是吸引用户注意力的利器，其成为了各 App 吸引用户，将用户带回到 App 本身，提升用户的活跃度的一种必要的方式。&lt;/p&gt;
&lt;p&gt;当然，过度的推送本身则是一件对用户影响特别大的事情，毕竟注意力被打断，因此合适的推送时机也是各个 App 开发者所要注意的，否则他的 App 就会成为用户勿扰名单里的一员了。&lt;/p&gt;
&lt;p&gt;之前刚开始学习 iOS 开发的时候还整理了下当时部署 iOS 远程推送的流程，详见：&lt;a href="http://hechen.info/2015/07/30/iOS-Push-Notification/"&gt;iOS 远端推送部署详解&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;接下来，我们大致回顾一下 iOS 平台关于推送都有哪些历程？&lt;/p&gt;
&lt;h2 id="历史"&gt;历史&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&amp;lt;= iOS 6&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;远程推送通知 （iOS 3）&lt;/li&gt;
&lt;li&gt;本地通知 （iOS 4）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;iOS 7 参考&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引入 Silent Remote Notifications&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;iOS 8 参考 &lt;a href="https://developer.apple.com/videos/play/wwdc2014/713/"&gt;WWDC 2014 Session 713&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引入 Actionable Notifications&lt;/li&gt;
&lt;li&gt;修改 Notification 的权限请求&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;iOS 9 参考 &lt;a href="https://developer.apple.com/videos/play/wwdc2015/720/"&gt;WWDC 2015 Session 720&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引入 Text Input Action&lt;/li&gt;
&lt;li&gt;UIUserNotificationActionBehavior&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;iOS 10 参考 &lt;a href="https://developer.apple.com/videos/play/wwdc2016/707"&gt;WWDC 707 Introduction to Notifications&lt;/a&gt; &amp;amp;&amp;amp; &lt;a href="https://developer.apple.com/videos/play/wwdc2016/708"&gt;WWDC 708 Advanced Notifications&lt;/a&gt;&lt;/p&gt;</description></item><item><title>如何使用UIBezierPath实现一个弹性视图动画</title><link>https://hechen.github.io/zh-cn/post/elastic-view-animation-using-uibezierpath/</link><pubDate>Wed, 02 Dec 2015 18:53:51 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/elastic-view-animation-using-uibezierpath/</guid><description>&lt;blockquote&gt;
&lt;p&gt;原文：&lt;a href="https://hackernoon.com/elastic-view-animation-or-how-i-built-dgelasticpulltorefresh-269a3ba8636e"&gt;Elastic view animation, or how I built DGElasticPullToRefresh&lt;/a&gt;
原作者 &lt;a href="https://twitter.com/gontovnik"&gt;@gontovnik&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/gontovnik/DGElasticPullToRefresh"&gt;DGElasticPullToRefresh&lt;/a&gt; 展示了如何实现一个弹性效果。效果如下图所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="DGElasticPullToRefresh.gif" loading="lazy" src="https://i.imgur.com/NzdoFS9.gif"&gt;&lt;/p&gt;
&lt;p&gt;开发环境：
Xcode 7
Swift 2.0&lt;/p&gt;
&lt;p&gt;要求：
开发者至少对 UIBezierPath 和 UIGestureRecognizer 有一定的了解.&lt;/p&gt;
&lt;h3 id="理解业务逻辑"&gt;理解业务逻辑&lt;/h3&gt;
&lt;p&gt;你可能从上面的效果图上可以看到一些端倪，这个动画中我们主要使用到了UIBezierPath来实现上面这种效果。
我们首先创建一个贝塞尔曲线路径的CAShapeLayer，然后当你的手指在屏幕上移动的时候我们将移动所有的控制点来呈现动画。每一个控制点会使用一个可见的UIView来表示。下面有几张图来演示它们是如何工作的，我将所有的控制点标识成了红色：&lt;/p&gt;
&lt;p&gt;&lt;img alt="1_vAmk8ulHh4OJji_X35zW4g" loading="lazy" src="media/1_vAmk8ulHh4OJji_X35zW4g.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="1_ru8KwJ6DZWXgJm1tm_Sw_Q" loading="lazy" src="media/1_ru8KwJ6DZWXgJm1tm_Sw_Q.png"&gt;&lt;/p&gt;
&lt;p&gt;第二章图片中将每个表示控制点的 View 的变量名称标记出来了，如L3，L2等。&lt;/p&gt;
&lt;p&gt;当你的手指释放的时候，我们就播放Spring动画，让所有的控制点向其初始位置以一定的回弹效果移动。当所有的视图在动画播放过程中，我们需要时刻计算并我们的贝塞尔曲线（每一帧都进行计算）。因此，我们准备使用CADisplayLink，CADisplayLink在主循环中运行而且每一帧都会去执行指定的方法。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display. - Apple doc&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;让我们开始Code吧~&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="build"&gt;Build&lt;/h3&gt;
&lt;p&gt;创建一个单视图控制器，然后将下面这些代码粘贴到viewController.swift文件的类声明中。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// MARK: -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// MARK: Vars
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;private let minimalHeight: CGFloat = 50.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;private let shapeLayer = CAShapeLayer()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// MARK: -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;override func loadView() {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; super.loadView()
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; shapeLayer.frame = CGRect(x: 0.0, y: 0.0, width: view.bounds.width, height: minimalHeight)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; shapeLayer.backgroundColor = UIColor(red: 57/255.0, green: 67/255.0, blue: 89/255.0, alpha: 1.0).CGColor
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; view.layer.addSublayer(shapeLayer)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: &amp;#34;panGestureDidMove:&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// MARK: -
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// MARK: Methods
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;func panGestureDidMove(gesture: UIPanGestureRecognizer) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if gesture.state == .Ended || gesture.state == .Failed || gesture.state == .Cancelled {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; } else {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; shapeLayer.frame.size.height = minimalHeight + max(gesture.translationInView(view).y, 0)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;override func preferredStatusBarStyle() -&amp;gt; UIStatusBarStyle {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; return .LightContent
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以上代码中，我们做的工作主要有以下几点：&lt;/p&gt;</description></item><item><title>Objective-C中Category的一点东西</title><link>https://hechen.github.io/zh-cn/post/objective-c%E4%B8%ADcategory%E7%9A%84%E4%B8%80%E7%82%B9%E4%B8%9C%E8%A5%BF/</link><pubDate>Mon, 14 Sep 2015 15:36:07 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/objective-c%E4%B8%ADcategory%E7%9A%84%E4%B8%80%E7%82%B9%E4%B8%9C%E8%A5%BF/</guid><description>&lt;p&gt;Objective-C中的分类（category）是一种编译时的手段，其允许我们通过给某个已知类添加方法来扩充该类的一种方式。当然这其中是有限制的，就是不能给已知类添加新的实例变量。&lt;/p&gt;
&lt;p&gt;如下代码展示：&lt;/p&gt;
&lt;p&gt;类&lt;code&gt;MyClass&lt;/code&gt;为一个简单的类，其中有实例方法 &lt;code&gt;-print&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#import &amp;lt;Foundation/Foundation.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; : &lt;span class="nc"&gt;NSObject&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;#import &amp;#34;MyClass.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@implementation MyClass
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- (void)print
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; NSLog(@&amp;#34;MyClass...&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@end
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们向为MyClass再添加一个方法Hello，那我们就可以用分类的方法实现，我们为其添加分类MyAddition1和MyAddition2，如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#import &amp;#34;MyClass.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="nl"&gt;(MyAddition1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nonatomic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#import &amp;#34;MyClass+MyAddition1.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="nl"&gt;(MyAddition1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@&amp;#34;hello!!!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中MyAddition为分类的名称，而文件名字约定俗成用“类名+扩展名”的形式。这样，我们就能够为MyClass类添加hello方法了，如下调用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#import &amp;#34;MyClass+MyAddition1.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt; &lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MyClass&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Category 的使用场景主要有以下几种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;需求变更，需要为已知类添加方法；&lt;/li&gt;
&lt;li&gt;将类的不同模块实现划分: a)具体可以将类的实现分开到不同的文件里面； b)将不同功能的分类文件交由不同的开发者实现；&lt;/li&gt;
&lt;li&gt;想为Apple基础类库添加自己需要的方法，实际上和1相似；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但是分类的使用目前也有需要注意的地方：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Category可以访问原有类的实例变量，但不能添加实例变量；&lt;/li&gt;
&lt;li&gt;Category中实现和原有类中相同签名的方法时，会覆盖原有类的方法；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但是这两点均可以通过其他方式实现：&lt;/p&gt;
&lt;h3 id="为分类添加实例变量"&gt;为分类添加实例变量&lt;/h3&gt;
&lt;p&gt;为分类添加实例变量主要通过关联对象的方法。如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#import &amp;#34;MyClass.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="nl"&gt;(MyAddition1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nonatomic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#import &amp;#34;MyClass+MyAddition1.h&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#import &amp;lt;objc/objc-runtime.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="nl"&gt;(MyAddition1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setName:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;objc_setAssociatedObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OBJC_ASSOCIATION_COPY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objc_getAssociatedObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="如果调用被分类覆盖掉的原方法"&gt;如果调用被分类覆盖掉的原方法&lt;/h4&gt;
&lt;p&gt;实际上，通过查看Objc runtime源码可以获知，分类方法并不是绝对意义上的覆盖原有类的方法，只是在调用的时候调用顺序导致而已，这涉及到Objc runtime的一些内容。&lt;/p&gt;</description></item><item><title>理解Objective-C运行时</title><link>https://hechen.github.io/zh-cn/post/understanding-the-objective-c-runtime/</link><pubDate>Mon, 07 Sep 2015 17:55:33 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/understanding-the-objective-c-runtime/</guid><description>&lt;p&gt;Objective-C 运行时对于刚刚踏入 Cocoa/Objective 世界的人是很容易忽
略的 Objective-C 语言的特性之一。原因就是尽管 Objective-C 是一门几个小时之内入门的语言，但是投身 Cocoa 的新手们会花费大量时间在 Cocoa 框架中，试图搞清楚他到底是怎么工作的。 我觉得每个开发者都应该对其有深入的了解，明白一些内部的实现细节，而不仅仅只知道代码 &lt;code&gt;[target doMethodWith:var]&lt;/code&gt; 会被编译器转换成 &lt;code&gt;objc_msgSend(target,@selector(doMethodWith:),var1);&lt;/code&gt; 而已。了解 Objective-C 运行时的原理有助于你对 Objective-C 语言有更深入的理解，清楚你得 App 是怎么运行的。我觉得这对无论是 Mac/iPhone 新手或者老手都会有所帮助。&lt;/p&gt;
&lt;p&gt;[TOC]&lt;/p&gt;
&lt;h4 id="objective-c运行时是开源的"&gt;Objective-C运行时是开源的&lt;/h4&gt;
&lt;p&gt;Objective-C 运行时是开源的，你可以随时从 &lt;a href="http://opensource.apple.com"&gt;Apple&lt;/a&gt; 获取到。实际上查看 Objective-C 运行时源码是我搞清楚这个语言是怎么运作的首选方法，而不是去查看和它相关的苹果文档。你可以到&lt;a href="http://opensource.apple.com/tarballs/objc4/objc4-437.1.tar.gz"&gt;这里&lt;/a&gt; 下载到运行时的源码（截止到译者翻译的时候，最新版本的文件是objc4-647.tar.gz）。&lt;/p&gt;
&lt;h4 id="动态-vs-静态"&gt;动态 Vs. 静态&lt;/h4&gt;
&lt;p&gt;Objective-C 是一门动态的面向对象语言，这意味着它可以将编译链接时决定的事情推迟到运行时进行。这就给了你很大的灵活性，你可以按照自己的需要重定向消息到适当的对象上，你甚至可以交换方法实现（译者注：method swizzling，方法调配，开发者常用此技术向原有实现中添加新功能）。而运行时可以使对象明白自己可以响应哪些消息，不能响应哪些消息（译者注：introspect 内省），并正确的派发消息。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;译者注： 内省（introspection）是面向对象语言和环境的一个强大特性，Objective-C和Cocoa在这个方面尤其的丰富。内省是对象揭示自己作为一个运行时对象的详细信息的一种能力。这些详细信息包括对象在继承树上的位置，对象是否遵循特定的协议，以及是否可以响应特定的消息。NSObject协议和类定义了很多内省方法，用于查询运行时信息，以便根据对象的特征进行识别。&lt;/p&gt;
&lt;p&gt;参考: &lt;a href="https://developer.apple.com/library/archive/documentation/General/Conceptual/CocoaEncyclopedia/Introspection/Introspection.html"&gt;Objective-C 的 Introspection&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们将这些特征和C语言进行对比来看，在C中，你从&lt;code&gt;main()&lt;/code&gt;函数开始，然后按顺序从上往下写你的代码逻辑或者执行函数方法。C结构体是无法将请求转发到其他目标对象来执行方法的。你很可能写了如下类似的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt; stdio.h &amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello World!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译器解析、优化然后将优化后的代码转换成如下的汇编语言：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;align&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mh"&gt;0x90&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;globl&lt;/span&gt; &lt;span class="n"&gt;_main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;_main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;Leh_func_begin1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pushq&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rbp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;Llabel1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;movq&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rbp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;Llabel2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;subq&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;Llabel3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;movq&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;movl&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;edi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;movl&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;ecx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;movq&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;xorb&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;al&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;al&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;leaq&lt;/span&gt; &lt;span class="n"&gt;LC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rcx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;movq&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rcx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rdi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;_printf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;movl&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;movl&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;eax&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;addq&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rsp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;popq&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;rbp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;Leh_func_end1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cstring&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;LC&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;asciz&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Hello World!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后将其和C库链接生成可执行文件。相比之下，Objective-C语言整个过程和上面类似，不过代码的产生依赖Objective-C运行时的具体表现（译者注：运行时按照不同情况，生成不同的代码吧）。当我们刚接触Objective-C语言的时候，我们可能被告知像如下代码&lt;/p&gt;</description></item><item><title>我们是如何创建iOS版的Guillotine菜单动画的</title><link>https://hechen.github.io/zh-cn/post/how-we-created-guillotine-menu-animation-for-ios/</link><pubDate>Tue, 01 Sep 2015 15:52:07 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/how-we-created-guillotine-menu-animation-for-ios/</guid><description>&lt;blockquote&gt;
&lt;p&gt;原文：&lt;a href="https://yalantis.com/blog/how-we-created-guillotine-menu-animation/"&gt;How We Created Guillotine Menu Animation for iOS&lt;/a&gt;
原作者 &lt;a href="https://twitter.com/johnsundell"&gt;@johnsundell&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你是否曾经有过这样的疑问？为什么app中几乎是清一色的&lt;strong&gt;侧&lt;/strong&gt;边栏（sidebar），为什么不把它做成&lt;strong&gt;top&lt;/strong&gt;Bar或者&lt;strong&gt;bottom&lt;/strong&gt;Bar，甚至&lt;strong&gt;corner&lt;/strong&gt;Bar呢？&lt;/p&gt;
&lt;p&gt;本文将要谈到的就是当前导航条动画的一个新趋势。&lt;/p&gt;
&lt;p&gt;动画很有趣，但更重要的是能发挥很大的作用，它们可以改变你思考问题的方式，使得你的产品更好用并提升的app整体的用户体验。接下来我们将要展示的是设计师&lt;strong&gt;Vitaly Rubtsov&lt;/strong&gt;的一个非常棒的点子：&lt;/p&gt;
&lt;p&gt;“每个设计师都有那么一刻感到无聊。因为几乎所有（对动画）的完善修补、裁剪以及规格设定都给他们留下了很少发挥想象的余地。而每当这些时候，我就会驱使自己打开Adobe After Effects软件然后创作一些比较有趣的东西。&lt;/p&gt;
&lt;p&gt;当我开始想我要创建一个什么东西的时候，我突然有个想法，通常侧边栏都从屏幕左侧划出，同时将所有的内容都移动到右侧位置。这种传统侧边栏的实现方式太过无聊了。那如果我们将侧边栏变成上边栏会怎么样呢？它从页面的上方掉落然后以一种特别的方式呈现，听起来很棒不是吗？“&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Vitaly&lt;/strong&gt;设计的topBar动画由我们的iOS开发工程师&lt;strong&gt;Maksym Lazebnyi&lt;/strong&gt;使用&lt;code&gt;swift&lt;/code&gt;语言实现，并且开发者给了它一个很有趣的名字—— &lt;strong&gt;Guillotine Menu&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Guillotine Menu Animation" loading="lazy" src="https://i.imgur.com/Q2GueMC.gif"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="我们是如何开发guillotine-menu的"&gt;我们是如何开发Guillotine Menu的？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;by Makssym Lazebnyi&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;实际上，我们的iOS团队见到过很多实现这种动画效果的方法。我们选择了其中一种方式实现，这种方式允许开发者在Storyboard中以任何方式自定义菜单。&lt;/p&gt;
&lt;p&gt;为了实现我们的转场动画（transitioning animation），我们创建了一个UIStoryboardSegue的子类和一个自定义动画管理器（custom animation controller）。基本上这就是你实现该动画所需要做的全部工作，除非你想让它更炫酷。当然我们也确实想这样做，因此还创建了一些辅助的类。&lt;/p&gt;
&lt;p&gt;整体上，你需要三个类以及一个&lt;code&gt;UIView&lt;/code&gt;的扩展类来创建这个动画，如下所示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GuillotineMenuSegue&lt;/code&gt;. 该类是继承自&lt;code&gt;UIStoryboardSegue&lt;/code&gt;类。我们使用它来模态显示菜单，并实现由 &lt;code&gt;GuillotineMenuTransitionAnimation&lt;/code&gt;类控制的呈现动画。 &lt;code&gt;GuillotineMenuSegue&lt;/code&gt;允许你为菜单添加透明度，当然本文并没有做这个工作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GuillotineMenuTransitionAnimation&lt;/code&gt;. 该类是为了自定义呈现 &lt;code&gt;GuillotineMenuViewController&lt;/code&gt; 类中视图的动画所用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GuillotineMenuViewController&lt;/code&gt;. 该类是一个UIViewController的子类，存放菜单视图所用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除此之外，我们还为UIView添加了扩展方法以便能为子视图添加约束来更好的适应父视图。&lt;/p&gt;
&lt;p&gt;接下来，我们逐一对每一个类进行阐述。&lt;/p&gt;
&lt;h4 id="guillotinemenusegue"&gt;GuillotineMenuSegue&lt;/h4&gt;
&lt;p&gt;这个类中没有什么特别的地方，我只提及一些关键点。&lt;/p&gt;
&lt;p&gt;在该类重载的init方法中，我们检查目标视图控制器（destination view controller）是否遵守&lt;code&gt;GuillotineAnimationProtocol&lt;/code&gt; 协议（该协议我们后面会讲到）。在重载的perform方法中我们将self设置成一个过渡动画的代理。&lt;/p&gt;
&lt;p&gt;在代理方法 &lt;code&gt;animationControllerForPresentedController&lt;/code&gt; 中我们使用关联对象将&lt;code&gt;GuillotineMenuSegue&lt;/code&gt;的实例对象（&lt;strong&gt;self&lt;/strong&gt;）关联到具体的将要呈现的视图控制器中，这样当menu view controller呈现在屏幕上的时候，segue实例不会被销毁。（译者注：代码如下）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UIViewControllerAnimatedTransitioning&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;animationControllerForPresentedController:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;presented&lt;/span&gt; &lt;span class="nf"&gt;presentingController:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;presenting&lt;/span&gt; &lt;span class="nf"&gt;sourceController:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;source&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 将segue示例self关联到将要呈现的试图控制器presented中，这样确保presented生命周期内segue实例不会被释放
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;objc_setAssociatedObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;presented&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OBJC_ASSOCIATION_RETAIN_NONATOMIC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;GuillotineTransitionAnimation&lt;/span&gt; &lt;span class="n"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nl"&gt;initWithMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;AnimationModePresentation&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id="guillotinemenutransitionanimation"&gt;GuillotineMenuTransitionAnimation&lt;/h4&gt;
&lt;p&gt;所有的动画处理逻辑都在这个类中实现。&lt;/p&gt;
&lt;p&gt;起初我们考虑使用 &lt;code&gt;animateWithDuration usingSpringWithDamping &amp;amp; initialSprintVelocity&lt;/code&gt;方法，但是当我们认真考虑这个动画之后我们改变了主意。我们需要实现的菜单动画中，当菜单从上方掉落之后，需要和父视图的左侧边界发生碰撞，产生碰撞效果。而上面方法中的回弹效果会穿过左边界（spring through the border of the superview），因此我们放弃了这个实现方式，转而采用了&lt;code&gt;UIDynamicAnimator&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>[257] Binary Tree Paths</title><link>https://hechen.github.io/zh-cn/post/leetcode-019-binarytreepaths/</link><pubDate>Tue, 18 Aug 2015 16:28:26 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/leetcode-019-binarytreepaths/</guid><description>&lt;h1 id="题目257-binary-tree-paths"&gt;题目：257. Binary Tree Paths&lt;/h1&gt;
&lt;p&gt;Given a binary tree, return all root-to-leaf paths.
For example, given the following binary tree:
1
/&lt;br&gt;
2 3&lt;br&gt;
5
All root-to-leaf paths are:
[“1-&amp;gt;2-&amp;gt;5”, “1-&amp;gt;3”]&lt;/p&gt;
&lt;h2 id="题意"&gt;题意：&lt;/h2&gt;
&lt;p&gt;难度不大，考察树的遍历&lt;/p&gt;
&lt;h2 id="解法"&gt;解法：&lt;/h2&gt;
&lt;p&gt;C++版本实现方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * Definition for a binary tree node.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * struct TreeNode {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * int val;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * TreeNode *left;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * TreeNode *right;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * };
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Solution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nl"&gt;public&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;binaryTreePaths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;visitTreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nl"&gt;private&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;visitTreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;-&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;int2Str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;nullptr&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;visitTreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;visitTreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;int2Str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;nValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ostringstream&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ss&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;nValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>[018] Length Of Last Word</title><link>https://hechen.github.io/zh-cn/post/leetcode-018-lengthoflastword/</link><pubDate>Tue, 18 Aug 2015 16:13:44 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/leetcode-018-lengthoflastword/</guid><description>&lt;h3 id="题目"&gt;题目：&lt;/h3&gt;
&lt;p&gt;Given a string s consists of upper/lower-case alphabets and empty space characters ’ ‘, return the length
of last word in the string.
If the last word does not exist, return 0.
Note: A word is defined as a character sequence consists of non-space characters only.
For example, Given s = “Hello World”, return 5.&lt;/p&gt;
&lt;h3 id="题意"&gt;题意：&lt;/h3&gt;
&lt;p&gt;难度不大，考虑所有边界情况即可。&lt;/p&gt;
&lt;h3 id="解法"&gt;解法：&lt;/h3&gt;
&lt;p&gt;C++版本实现方法1：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 从右往左依次遍历即可
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Solution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nl"&gt;public&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;lengthOfLastWord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;leetCode Oj系统评判结果如下图所示：&lt;/p&gt;</description></item><item><title>iOS 远端推送部署详解</title><link>https://hechen.github.io/zh-cn/post/ios-push-notification/</link><pubDate>Thu, 30 Jul 2015 14:30:00 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/ios-push-notification/</guid><description>&lt;p&gt;最近几天被iOS的推送部署给搞懵了，现在特地整理下和大家进行分享。&lt;/p&gt;
&lt;h1 id="ios远端推送机制"&gt;iOS远端推送机制&lt;/h1&gt;
&lt;p&gt;APNS，全称为Apple Push Notification service，是苹果通知推送服务中最重要的一环。它是苹果通知推送服务器，为所有iOS设备以及OS X设备提供强大并且可靠的推送通知服务。每个注册通知服务的设备都会和该服务器进行长连接，从而实时获取推送通知。即使当前APP不在运行状态，当通知到达的时候也会有提示发生，最常见的就是短信服务。&lt;/p&gt;
&lt;p&gt;每一个App必须向APNs注册通知服务，APNs会返回给设备一个DeviceToken，该Token为APNs上针对该设备的唯一标示符。App需要将该DeviceToken返给自身的Server端保存后续使用，如下所示。&lt;/p&gt;
&lt;p&gt;&lt;img alt="DeviceToken的操作流程" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPushshare%20the%20device%20Token.png"&gt;&lt;/p&gt;
&lt;p&gt;当App开发者的server需要向特定设备推送通知时，就使用DeviceToken和固定格式数据（Push payload）发给APNs，然后APNs就会向DeviceToken指定的设备推送通知了，具体流程如下所示，单一推送&lt;/p&gt;
&lt;p&gt;&lt;img alt="通知方推送一条远端通知给客户端代码的整个流程" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPushPushing%20a%20remote%20notification%20from%20a%20provider%20to%20a%20client%20app.png"&gt;&lt;/p&gt;
&lt;p&gt;或者多方通知，APNs都能一一对应，靠的就是之前我们提供给它的DeviceToken。&lt;/p&gt;
&lt;p&gt;&lt;img alt="多个通知方向向不同的客户端推送通知的流程示意" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPushPushing%20remote%20notifications%20from%20multiple%20providers%20to%20multiple%20devices.png"&gt;&lt;/p&gt;
&lt;h2 id="本地推送证书配置"&gt;本地推送证书配置&lt;/h2&gt;
&lt;p&gt;打开你mac的钥匙串访问，然后点击钥匙串访问&lt;/p&gt;
&lt;p&gt;&lt;img alt="打开钥匙串" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e9%92%a5%e5%8c%99%e4%b8%b2.png"&gt;&lt;/p&gt;
&lt;p&gt;随后它会弹出一个窗口 用户电子邮件信息&lt;/p&gt;
&lt;p&gt;&lt;img alt="生成CSR文件" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a61.png"&gt;&lt;/p&gt;
&lt;p&gt;就填写你苹果开发者账号的名称即可（应该是一个邮件名称），点击保存到磁盘的选项，点击继续，点击存储，文件名为：CertificateSigningRequest.certSigningRequest。&lt;/p&gt;
&lt;p&gt;&lt;img alt="保存生成的CSR文件" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a62.png"&gt;&lt;/p&gt;
&lt;p&gt;然后我们打开&lt;a href="developer.apple.com"&gt;苹果开发者中心&lt;/a&gt; 进入 Member Center&lt;/p&gt;
&lt;p&gt;&lt;img alt="苹果开发者中心" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a63.png"&gt;&lt;/p&gt;
&lt;p&gt;然后点击左侧列表中任意一项进入详情页面，&lt;/p&gt;
&lt;p&gt;&lt;img alt="开发者个人首页选项" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a64.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="选择IOS Apps中列表项" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a65.png"&gt;&lt;/p&gt;
&lt;h2 id="app-id"&gt;APP ID&lt;/h2&gt;
&lt;p&gt;首先我们需要为我们要开发的APP建立身份信息，就是AppID，如图所示，点击左侧&lt;/p&gt;
&lt;p&gt;&lt;img alt="添加AppID" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPushAPPID1.png"&gt;&lt;/p&gt;
&lt;p&gt;点击添加按钮进入注册页面，我们需要输入App Id的名字以及BundleID，其中BundleID不能有通配符，否则无法具备推送功能，然后在下面的APP Service中勾选Push Notification一项&lt;/p&gt;
&lt;p&gt;&lt;img alt="填写BundleID以及App ID Description" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPushAPPID2.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="选择App Service" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPushAPPID3.png"&gt;&lt;/p&gt;
&lt;p&gt;点击下一步，然后确认提交即可，大家注意到Push Notification一项为Configurable，这是因为我们还没有为该AppID生成推送证书，等推送证书生成完毕之后可以再回来查看该AppID 的状态。&lt;/p&gt;
&lt;p&gt;&lt;img alt="确认提交App ID" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a613.jpg"&gt;&lt;/p&gt;
&lt;h2 id="certificates"&gt;Certificates&lt;/h2&gt;
&lt;p&gt;其次，我们需要生成开发者证书和推送证书，如下图所示，点击左侧Cerifications列表，选择添加进入下一页面，&lt;/p&gt;
&lt;p&gt;&lt;img alt="添加证书" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a611.png"&gt;&lt;/p&gt;
&lt;p&gt;如果您的页面如图所示为灰色不可选，说明您已经拥有了开发者证书。就不需要再次生成了，如果可选就选择该选项，&lt;/p&gt;
&lt;p&gt;&lt;img alt="选择证书类型" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a67.png"&gt;&lt;/p&gt;
&lt;p&gt;接下来进入以下界面，选择你之前添加的AppID，之后点击Continue即可，&lt;/p&gt;
&lt;p&gt;&lt;img alt="选择需要绑定证书的App ID" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a68.png"&gt;&lt;/p&gt;
&lt;p&gt;然后选择之前我们保存在本地的CSR文件CertificateSigningRequest.certSigningRequest，点击Generate就生成了开发者的证书。&lt;/p&gt;
&lt;p&gt;&lt;img alt="上传本机CSR文件" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a69.png"&gt;&lt;/p&gt;
&lt;p&gt;同理我们需要生成推送测试证书，生成流程和开发者证书类似，只是在证书类型页面，选择的证书类型换成了Apple Push Notification service SSL。&lt;/p&gt;
&lt;p&gt;&lt;img alt="选择生成证书类型" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a610.png"&gt;&lt;/p&gt;
&lt;p&gt;当我们生成好推送证书之后再回头看我们之前创建的AppId，能够看Push Notifications一项已经为Enabled了。当然发布推送证书配置完毕之后，Distribution一项也显示为Enable。&lt;/p&gt;
&lt;p&gt;&lt;img alt="再次查看APPID 状态" loading="lazy" src="http://7xilk1.com1.z0.glb.clouddn.com/iosPush%e8%af%81%e4%b9%a612.jpg"&gt;&lt;/p&gt;
&lt;h2 id="provisioning-profiles"&gt;Provisioning Profiles&lt;/h2&gt;
&lt;p&gt;第三步，需要生成Provisioning Profiles，该文件其实就是以上的证书、AppId以及设备信息的打包集合，我们只要在不同的场景下生成不同类型Provisioning Profiles即可，它会在后续打包ipa文件的时候被嵌入安装包内。&lt;/p&gt;</description></item></channel></rss>