OC时代,第三方库为现有系统类添加方法为了防止后续和系统函数冲突,采用了添加自定义前缀的方式,比如Masonry使用mas_前缀

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview);
}];

Swift因为有着点语法的良好提示,所以现在更流行通过添加命名空间去添加拓展,比如SnapKitsnp

box.snp.makeConstraints { (make) -> Void in
     make.width.height.equalTo(50)
     make.center.equalTo(self.view)
}

通过命名空间去拓展,不仅代码提示更加顺畅,而且不用频繁的去用import导入库,所以在Swift中用的更多。

实现原理

命名空间形势的拓展,本质上是用一个结构体去保存了创建的对象,比如HDSwiftCommonTools这个库的这段字符串加密

let string = "是胡不是霍"
_ = string.hd.encryptString(encryType: .md5)

string.hd是创建了一个结构体HDNameSpace,这个结构体实现了encryptString(encryType: .md5)的方法

extension HDNameSpace {
    func encryptString(encryType: HDEncryType, lowercase: Bool = true) -> String {
        ...
    }
}

string.hd除了创建结构体,还可以把string这个变量传给结构体存起来,这样在encryptString这个函数里,HDNameSpace就可以通过存起来的变量去操作了。

代码实现

命名空间的结构体,HDNameSpace可以自由命名,这里只是个示例

public struct HDNameSpace <T> {
    let object: T       //存储的实例对象
    
    internal init(object: T) {
        self.object = object
    }
}

针对字符串最简单的实现,hd是一个示例,自己可以随意命名

extension String {
    var hd :HDNameSpace<String> {
        return HDNameSpace(object: self)
    }
}

public extension HDNameSpace where T == String {
    func ssssss() -> Void {
        print(object)
    }
}

这样就实现了string.hd.ssssss(),这样调用就会把string打印出来了。

更高阶用法

为了更加方便统一,这里可以使用协议约束一下命名,防止出现String调用的时候是hdView调用的时候关键词变成了md这种智障问题

//实现命名空间需遵守的协议
public protocol HDNameSpaceWrappable {
    associatedtype WrapperType
    var hd: WrapperType { get }
    static var hd: WrapperType.Type { get }
}

//协议默认的实现方式
public extension HDNameSpaceWrappable {
    var hd: HDNameSpace<Self> {
        return HDNameSpace(object: self)
    }
}

这样刚才的String的拓展直接写成遵守协议就行了,有默认实现,可以不用再自己写hd实现了

extension String: HDNameSpaceWrappable {
    
}
public extension HDNameSpace where T == String {
    func ssssss() -> Void {
        print(object)
    }
}

注意事项

1、public extension HDNameSpace where T == String这句话是约束了对应类型

where 后面的 WrappedType 约束可以使用 == 或者 : ,两者是有区别的。如果扩展的是值类型,比如 String,Date 等,就必须使用 == ,如果扩展的是类,则两者都可以使用,区别是如果使用 == 来约束,则扩展方法只对本类生效,子类无法使用。如果想要在子类也使用扩展方法,则使用 : 来约束。

2、静态方法,类方法可以通过加static关键词去拓展

3、如果对父类已经拓展实现了HDNameSpaceWrappable 协议,子类就不需要再实现了,会报错哦

参考文章


☟☟可点击下方广告支持一下☟☟

最后修改:2020 年 07 月 10 日
请我喝杯可乐,请随意打赏: ☞已打赏列表