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