跳过正文
  1. Posts/

Alamofire 和 RxSwift 中的 .af 以及 .rx 扩展是怎么实现的

目录

今天继续来一篇水文,关于 Alamofire 和 RxSwift 两个组件中扩展后缀 .af 以及 .rx 是怎么实现的。相信用过的 ( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ 都看过了。我这里权当自己的记录流水账了。

先来看 Alamofire 中关于 af 扩展的实现:

Alamofire

使用 Alamofire 扩展的方式如下:

struct Demo {}
extension Demo: AlamofireExtended {}
extension AlamofireExtension where ExtendedType == Demo {
	func printSomething() {
		print("Something arrived.")
	}
}
let d = Demo()
d.af.printSomething()

这里主要有两点:

  1. 为将要使用的类 Demo 扩展 AlamofireExtended 协议,也就是增加 af 扩展属性,其返回的是一个封装对象 AlamofireExtension
  2. AlamofireExtension 对象(1 中返回的封装类型)扩展专属于 Demo 这个类型的方法;

说实话,这里用来封装元类型信息的结构体名称和扩展协议名称一样,我初次看的时候确实是蒙的。相对于 Alamofire 的命名来说,个人更喜欢 RxSwift 的命名。

接下来是 RxSwift 中 Rx 扩展的实现:

RxSwift

可以看到,整个使用方式上是完全相同的。仅仅是各项名字不同。

所以我们可以总结这种方式的使用路径,如何为我们自己开发的组件扩充命名空间,具体有三个地方:

声明扩展属性
#

为了能够支持实例变量和类型两者,需要分别增加两个计算属性:

  • 一个是 static 的,提供给类型使用;
  • 一个是实例变量,提供给单个实例来用;

封装元类型信息
#

为了能够使得 .af/.rx 这些扩展属性也能够获得当前实例或者类型的元信息,不约而同的使用了结构体封装的形式,通过泛型类型实现。我们知道这个封装对象内部就是记录的就是 self

我们可以通过编译器提示来看下扩展返回的类型是什么。

Compiler Inference

从 print 这个方法可以推断出,这个类型是个 AlamofireExtension 对象(因为我们是针对该类型增加的扩展方法),并且其内部有个变量 type 就是我们扩展的类型 Demo。而我们为该对象扩展的方法 printSomething 也能够在实例是 Demo 类型的时候触发。

扩展目标类
#

我们已经知道扩展后缀拿到的是一个携带了关联类型的对象,因为有了关联类型,所以才能够通过 Where 子句写出针对不同类型存在的专属方法。

按照这个步骤,我们可以在自己的工程中写属于自己模块的扩展。

    import Foundation
    
    // We implemented a module named Wonderful.
    // Extension name will be named as wf
    
    // Step 0.
    // Encapsulate a type which is unknown until now.
    struct Extensible<EncapsulatedType> {
        let type: EncapsulatedType
        init(_ type: EncapsulatedType) {
            self.type = type
        }
    }
    
    // Step 1.
    // Extension a type to add two properties. a static var and a var
    protocol WonderfulExtension {
        associatedtype ExtendedType
        
        // static entry point
        static var wf: Extensible<ExtendedType>.Type { get set }
        // instance entry point
        var wf: Extensible<ExtendedType> { get set }
    }
    
    // Step 2.
    extension WonderfulExtension {
        static var wf: Extensible<Self>.Type {
            set { }
            get { return Extensible<Self>.self }
        }
        
        var wf: Extensible<Self> {
            set { }
            get { return Extensible(self) }
        }
    }
    
    // Step3.
    // Extend the type we want to, which the type will have wf var.
    struct Ordinary {}
    extension Ordinary: WonderfulExtension {}
    
    // Step4.
    // Restrict methods in the scope of type we want to extend
    extension Extensible where EncapsulatedType == Ordinary {
        func wow() {
            print("Wow, Wonderful extension.")
        }
    }
    
    // Use methods of wf extension
    let obj = Ordinary()
    obj.wf.wow()

总体上对于这种形式,带来两个显著的好处:

  1. 明确作用域,告知调用者调用的专属方法属于该组件相关;
  2. 提供该扩展的组件自身就更容易被扩展了(打上了烙印),也有了 RxSwift 所衍生的各种组件;

所以,这段代码中涉及的 Swift 类型系统中的几个关键支持:

  1. 关联类型, Associated Type
  2. 泛型系统, Generic
  3. 扩展的默认实现, Extension Default Implementation
Overview

相关文章

Swift 中的消息派发

什么是消息派发? # 消息派发,英文名称 Method Dispatch,是指程序在运行过程中调用某个方法的时候决议使用哪个具体指令的过程。消息派发的行为在我们代码中时时刻刻的在发生。了解消息派发的机制对于我们日常写出相对高效的代码也是有利的,日常 Coding 的时候遇到一些派发相关的问题,也能做到心里有数。

Protocol Extension

·2 分钟
Protocol 作为 Swift 生态的最重要的组成部分(没有之一),其搭建起了整个语言生态的各个组成部分。

Codable && Tuple

·2 分钟
During my learning of Swift, many interesting things I will find. Codable is one of them. Today, I defined a model with a tuple type, then Xcode told me some error. Codes may like as below. You may want Xcode automatically complete all the codable stuff. However, life is hard. Codes like these can even not be compiled. Xcode will tell you name cannot be synthesize the Person because of the FullName.

一道 Swift Quiz

·1 分钟
这两天在 Twitter 上看到一道题目,主要是考察 overload 和 type(of:) 的知识点,本文仅做记录,关于 MetaType 会单独写一篇文章来总结。

@autoclosure && @escape

·3 分钟
我们知道在 swift 中,闭包(closure)是一等公民,因此可以被当作参数传递,在学习 swift 的过程中经常会看到某些关键字修饰该闭包,@autoclosure, @escape 就是其中比较常见的两种关键字。