<?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>Pwt on Chen</title><link>https://hechen.github.io/zh-cn/tags/pwt/</link><description>Recent content in Pwt 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/pwt/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>Swift 中的消息派发</title><link>https://hechen.github.io/zh-cn/post/messagedispatchinswift/</link><pubDate>Sun, 15 Sep 2019 20:56:50 +0000</pubDate><guid>https://hechen.github.io/zh-cn/post/messagedispatchinswift/</guid><description>&lt;p&gt;&lt;img alt="What is the method dispatch" loading="lazy" src="https://i.imgur.com/ggQZyRp.png"&gt;&lt;/p&gt;
&lt;h1 id="什么是消息派发"&gt;什么是消息派发？&lt;/h1&gt;
&lt;p&gt;消息派发，英文名称 Method Dispatch，是指程序在运行过程中调用某个方法的时候决议使用哪个具体指令的过程。消息派发的行为在我们代码中时时刻刻的在发生。了解消息派发的机制对于我们日常写出相对高效的代码也是有利的，日常 Coding 的时候遇到一些派发相关的问题，也能做到心里有数。&lt;/p&gt;
&lt;p&gt;对于编译型语言来讲，有主要三种类型的方法派发方式：Direct Dispatch，Table Dispatch 以及 Message Dispatch，前者也被称作 Static Dispatch，后两个为 Dynamic Dispatch。&lt;/p&gt;
&lt;h1 id="方法派发类型"&gt;方法派发类型&lt;/h1&gt;
&lt;p&gt;本质上来讲，派发的目的就是告诉 CPU，在某个特定方法被调用的时候去内存的哪个地址去读执行代码。下面我们先了解下这三种类型的派发形式，这三种可以说各有优劣。&lt;/p&gt;
&lt;h2 id="direct-dispatch"&gt;Direct Dispatch&lt;/h2&gt;
&lt;p&gt;直接派发也叫静态派发。它是这三种形式中最快速的，不仅仅是底层翻译的汇编指令少，也是因为编译器可以针对这种情况做更多优化的事情，比如说函数内联等。C 语言就是这种的典型代表，然而，对于日渐复杂的编程场景来说，静态派发限制非常大，我们必须在代码运行之前把事情安排的明明白白的，这个极大的限制了代码书写的灵活性。一句话总结，编译器在编译期间就已经确定了的推断路径，运行期间按照既定路线走就行。&lt;/p&gt;
&lt;h2 id="table-dispatch"&gt;Table Dispatch&lt;/h2&gt;
&lt;p&gt;函数表派发这种是编译型语言中最常见的动态派发实现形式，编译器层面使用一个表格结构来存储类型声明中的每一个函数指针。C++ 语言把这种表格称作虚函数表（virtual table，简称 V-Table），而在 Swift 中，针对拥有继承的 Class 类型来说，依然采用了 V-Table 这种实现形式达到对多态的支持，而针对值类型由于 Protocol 产生的多态而采用了另外一种函数表派发形式，这个表格被称为协议目击表 （Protocol Witness Table，简称 PWT），这个暂时略去不表。&lt;/p&gt;
&lt;h3 id="v-table"&gt;V-Table&lt;/h3&gt;
&lt;p&gt;对于 V-Table 的应用场景下，每一个类都会维护一个函数表，里面记录着该类所有的函数指针，主要包含：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;由父类继承而来的方法执行地址；&lt;/li&gt;
&lt;li&gt;如果子类覆写了父类方法的话，表格里面就会保存被重载之后的函数。&lt;/li&gt;
&lt;li&gt;子类新添加的函数会插入到这个表格的末尾&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在程序运行期间会根据这个表去查询真正要调用的函数是哪一个。这种特性就极大的提升了代码的灵活性，也是 Java，C++ 等语言得以支持多态这种语言特性的基石。当然，相对于静态派发而言，表格派发则多了很多的隐式花销，因为函数调用不再是直接调用了，而是需要通过先行查表的形式找到真实的函数指针来执行，编译器也无法再进行诸如 inline 等编译期优化了。&lt;/p&gt;
&lt;p&gt;我们以 WWDC 的某个例子来大概说明下 V-Table 的具体派发过程，如下代码，共有三个 Class，其中 Drawable 是基类，子类化的 Point 和 Line。&lt;/p&gt;
&lt;p&gt;&lt;img alt="image-20190919233507171" loading="lazy" src="https://i.imgur.com/49YUt1Y.png"&gt;&lt;/p&gt;</description></item></channel></rss>