之前在使用 Kingfisher、RxSwift 的时候,一直对 .rx 及 .kf 的实现比较疑惑,不知道其实现原理。
这篇文章我们就来打造一个专属自己的命名空间。
介绍 Swift 的命名空间是基于 module 而不是在代码中显式地指明,每个 module 代表了 Swift 中的一个命名空间。也就是说,同一个 target 里的类型名称还是不能相同的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // MyFramework.swift // 这个文件存在于 MyFramework.framework 中 public class MyClass { public class func hello() { print("hello from framework") } } // MyApp.swift // 这个文件存在于 app 的主 target 中 class MyClass { class func hello() { print("hello from app") } }
在可能出现冲突的地方,我们需要在类型名称前面加上 module 的名字 (也就是 target 的名字):
1 2 3 4 5 // 使用哪个 MyClass,取决于是在哪个 target 中调用 MyClass.hello() // hello from framework MyFramework.MyClass.hello()
自己的命名空间 上面的说明虽然为我们解决了命名冲突的问题,但是我们应该怎样实现类似于 .rx、.kf 这样自己的命名空间呢?
下面我们就来一步步讲解。
原理 原理: 对原类型进行一层封装。然后,对这个封装进行自定义的方法扩展。
现在你可能不太理解,下面我们就一步步的来实现自己的命名空间。
代码实现
对原类型进行一层封装
1 2 3 4 5 6 7 8 // 定义泛型类 // 首先定义一个泛型类 JTKit,使用泛型 Base public struct JTKit<Base> { private let base: Base public init(_ base: Base) { self.base = base } }
定义了一个 JTWrappable 协议,这个协议代表了支持 namespace 形式的扩展。并紧接着给这个协议 extension 了默认实现。这样实现了这个协议的类型就不需要自行实现协议所约定的内容了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 定义泛型协议 // 定义支持泛型的协议 JTWrappable,并通过协议扩展提供协议的默认实现,返回实现泛型类 JTKit 的对象自身。 public protocol JTWrappable { associatedtype WrappableType var jt: WrappableType { get } } // 协议的扩展 public extension JTWrappable { var jt: JTKit<Self> { get { return JTKit(self) } } }
associatedtype: 相关类型。意思也就是被associatedtype关键字修饰的变量,相当于一个占位符,而不能表示具体的类型。具体的类型需要让实现的类来指定。
需要实现命名空间的类提供 JTWrappable 协议扩展,并实现相关命名空间的对象方法(主要是扩展新的方法,如代码中的 testMethod 方法)
1 2 3 4 5 6 7 8 9 10 11 12 extension String: JTWrappable {} // String 命名空间 jt 中的函数 extension JTKit where Base == String { public var testMethod: String { return base + "namespace" } public func method(str: String) -> String { return base + str } }
1 2 3 4 5 6 7 let str = "Hello " print(str.jt.testMethod) print(str.jt.method(str: "namespace")) ---输出结果:--- Hello namespace Hello namespace
参考资料 Swifter 100 个 SWift 必备 Tips
Versatile namespace in Swift