Swift 命名空间

4,423 阅读2分钟

之前在使用 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

参考资料

Swifter 100 个 SWift 必备 Tips

Versatile namespace in Swift