<?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>Tuple on Chen</title><link>https://hechen.github.io/zh-cn/tags/tuple/</link><description>Recent content in Tuple on Chen</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sun, 29 Sep 2019 10:30:30 +0800</lastBuildDate><atom:link href="https://hechen.github.io/zh-cn/tags/tuple/index.xml" rel="self" type="application/rss+xml"/><item><title>Alamofire 和 RxSwift 中的 .af 以及 .rx 扩展是怎么实现的</title><link>https://hechen.github.io/zh-cn/post/alamofire-rxswift-af-rx/</link><pubDate>Sun, 29 Sep 2019 10:30:30 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/alamofire-rxswift-af-rx/</guid><description>&lt;p&gt;今天继续来一篇水文，关于 Alamofire 和 RxSwift 两个组件中扩展后缀 .af 以及 .rx 是怎么实现的。相信用过的 (￣ω￣(￣ω￣〃 (￣ω￣〃)ゝ 都看过了。我这里权当自己的记录流水账了。&lt;/p&gt;
&lt;p&gt;先来看 Alamofire 中关于 af 扩展的实现：&lt;/p&gt;
&lt;p&gt;&lt;img alt="Alamofire" loading="lazy" src="https://i.imgur.com/AbPIzgX.png"&gt;&lt;/p&gt;
&lt;p&gt;使用 Alamofire 扩展的方式如下：&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;struct&lt;/span&gt; &lt;span class="nc"&gt;Demo&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;extension&lt;/span&gt; &lt;span class="nc"&gt;Demo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AlamofireExtended&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;extension&lt;/span&gt; &lt;span class="nc"&gt;AlamofireExtension&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;ExtendedType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Demo&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;func&lt;/span&gt; &lt;span class="nf"&gt;printSomething&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="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Something arrived.&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="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;let&lt;/span&gt; &lt;span class="nv"&gt;d&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Demo&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;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;af&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printSomething&lt;/span&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;ol&gt;
&lt;li&gt;为将要使用的类 Demo 扩展 &lt;code&gt;AlamofireExtended&lt;/code&gt; 协议，也就是增加 af 扩展属性，其返回的是一个封装对象 &lt;code&gt;AlamofireExtension&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;为 &lt;code&gt;AlamofireExtension&lt;/code&gt; 对象（1 中返回的封装类型）扩展专属于 Demo 这个类型的方法；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;说实话，这里用来封装元类型信息的结构体名称和扩展协议名称一样，我初次看的时候确实是蒙的。相对于 Alamofire 的命名来说，个人更喜欢 RxSwift 的命名。&lt;/p&gt;
&lt;p&gt;接下来是 RxSwift 中 Rx 扩展的实现：&lt;/p&gt;
&lt;p&gt;&lt;img alt="RxSwift" loading="lazy" src="https://i.imgur.com/m5O7lo5.png"&gt;&lt;/p&gt;
&lt;p&gt;可以看到，整个使用方式上是完全相同的。仅仅是各项名字不同。&lt;/p&gt;
&lt;p&gt;所以我们可以总结这种方式的使用路径，如何为我们自己开发的组件扩充命名空间，具体有三个地方：&lt;/p&gt;
&lt;h3 id="声明扩展属性"&gt;声明扩展属性&lt;/h3&gt;
&lt;p&gt;为了能够支持实例变量和类型两者，需要分别增加两个计算属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个是 static 的，提供给类型使用；&lt;/li&gt;
&lt;li&gt;一个是实例变量，提供给单个实例来用；&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="封装元类型信息"&gt;封装元类型信息&lt;/h3&gt;
&lt;p&gt;为了能够使得 &lt;code&gt;.af/.rx&lt;/code&gt; 这些扩展属性也能够获得当前实例或者类型的元信息，不约而同的使用了结构体封装的形式，通过泛型类型实现。我们知道这个封装对象内部就是记录的就是 self&lt;/p&gt;</description></item><item><title>Protocol Extension</title><link>https://hechen.github.io/zh-cn/post/protocol-extension/</link><pubDate>Thu, 08 Aug 2019 19:00:20 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/protocol-extension/</guid><description>&lt;p&gt;Protocol 作为 Swift 生态的最重要的组成部分（没有之一），其搭建起了整个语言生态的各个组成部分。&lt;/p&gt;
&lt;p&gt;相对于继承而言，Protocol 的几个比较直观的优势：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;无需必须去强制继承某个类；&lt;/li&gt;
&lt;li&gt;通过协议可以改造已经存在的类型；&lt;/li&gt;
&lt;li&gt;适用范围更大一些，使得 struct 和 enum 这些值类型也能够继承能力&lt;/li&gt;
&lt;li&gt;Swift 语言本身是不支持多继承的，你需要花费精力去纠结继承哪个 class，一旦出现不同的能力分散在不同父类的情况，就更加纠结了，你甚至需要去修改原有的父类；&lt;/li&gt;
&lt;li&gt;继承的话，还需要考虑 override 父类方法的问题，比如调用 super 方法的时机问题；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这篇文章想记录下 Protocol Extension 中的一点区别。&lt;/p&gt;
&lt;p&gt;我们知道 Swift Protocol 中是没有 optional 关键字的，因此只要是在 Protocol 定义的方法，即为 Protocol Requirements，符合该协议的类型就必须实现，否则是不完整的。比如，我们自己实现了 TableView，定义了这么多 delegate 协议方法，要求调用方全都提供，就太不人道了😢&lt;/p&gt;
&lt;p&gt;&lt;img alt="Protocol" loading="lazy" src="https://i.imgur.com/yA76SiN.png"&gt;&lt;/p&gt;
&lt;p&gt;因此，我们会通过对 Protocol 进行扩展，给该协议方法增加缺省实现，剩余的方法则是你需要调用方必须实现的方法。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Optional Protocol" loading="lazy" src="https://i.imgur.com/MRA0k6z.png"&gt;&lt;/p&gt;
&lt;p&gt;如果针对某个协议 P，我们扩展 P 给其增加某个协议方法有两种形式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;直接在 Protocol 定义里定义新方法，该方法成为实现该协议必须实现的方法；&lt;/li&gt;
&lt;li&gt;为 Protocol 增加扩展方法，该方法并不一定要求符合该协议的类型进行实现；&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这两者有什么区别呢？ 我们看代码&lt;/p&gt;
&lt;p&gt;&lt;img alt="Static Dispatch" loading="lazy" src="https://i.imgur.com/T3filbG.png"&gt;&lt;/p&gt;
&lt;p&gt;发现 s 调用的是我们为 S 结构体增加的扩展方法，而 s2 调用的是 P 协议的扩展方法，尽管实体对象的动态类型是 S，但是因为声明的静态类型不一样，调用结果也不同。&lt;/p&gt;
&lt;p&gt;对于 1 中的方法，运行时进行动态派发，也就是真实根据其具体类型来做决议，2 中的方法是进行静态派发，也就是说你声明的该对象是什么类型，就调用该类型的方法。 以上述的代码为例，s1 的静态类型由编译器推导为 S，而 s2 的静态类型声明为 P ，因此二者在调用扩展协议方法时候的表现不一致。&lt;/p&gt;</description></item><item><title>Codable &amp;&amp; Tuple</title><link>https://hechen.github.io/zh-cn/post/tuple-codable/</link><pubDate>Mon, 10 Jun 2019 23:50:54 +0800</pubDate><guid>https://hechen.github.io/zh-cn/post/tuple-codable/</guid><description>&lt;p&gt;While learning Swift, I keep finding interesting things. Codable is one of them.&lt;/p&gt;
&lt;p&gt;Today, I defined a model with a tuple type, then Xcode gave me an error. The code might look like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Codable Person" loading="lazy" src="https://i.imgur.com/c67KrA8.png"&gt;&lt;/p&gt;
&lt;p&gt;You may want Xcode to automatically complete all the codable stuff. However, life is hard. Code like this cannot even be compiled. Xcode will tell you that it cannot synthesize Codable for Person because of FullName.&lt;/p&gt;</description></item></channel></rss>