Swift Extension 实现前缀功能

为了避免命名冲突,在需要对系统类型进行扩展时,我们需要在扩展的方法前面添加一个前缀,类似“命名空间”的功能,比如:

"ABC123456".abc.test()

其中,test() 是我们为 String 扩展的方法,abc 就是一个前缀。怎么实现的呢?

首先,我们需要定义一个结构体,用来定义这个“前缀”。

一. 定义结构体

struct Abc<Base> {
    var base: Base
    init(_ base: Base) {
        self.base = base
    }
}

结构体的名称就是前缀的名称。 定义了一个泛型,因为我们想让这个前缀能够在泛型中使用。也就是说因为这个泛型,我们的前缀不仅在 String 类型,在其它类型、甚至是自定义类型中也能使用。

base 属性是一个泛型类型,它的类型暂时不能确定,需要在 init 方法中确定。
在 init 方法中,可以传入一个对象,并用该对象的类型来初始化泛型类型。同时将这个对象保存到 base 属性中以便以后用到。

为了方便使用,我们先定义一个协议,然后利用协议扩展提供一个计算属性:

protocol AbcProtocol {}
extension AbcProtocol {
    var abc: Abc<Self> {      // 1
        set {}                // 2
        get { Abc(self) }     // 3
    }
}

  1. 定义一个计算属性,其类型是我们前面定义的结构体。
  2. 必须,否则编译器报错。
  3. 实例化 Abc 对象返回。同时将 self 传入到 base 属性,同时明确泛型的类型。

这样当我们对其它类型进行扩展时可以适用这个协议,这样就有一个现成的 abc 属性了。然后在通过扩展 Abc 结构体来添加新的方法。

二. 定义扩展

假设我们要为 String 扩展一个 test 的方法,那么我们可以这样定义一个扩展:

extension String: AbcProtocol{}            // 1
extension NSString: AbcProtocol()          // 2
extension Abc where Base: ExpressibleByStringLiteral{ // 3
    func test() {
        print("\(base as! String)")         // 4
    }
}
  1. 明确 String 继承了 AbcProtocol,获得 abc 属性。
  2. 明确 NSString 继承了 AbcProtocol,因为 NSMutableString 继承自 NSString,所以也自动获得了 abc 属性。
  3. 对 Abc 结构体进行扩展,并指明了这个扩展只能应用于实现了 ExpressibleByStringLiteral 协议的类型。所有能够用字符串字面量进行赋值的类型都遵守了ExpressibleByStringLiteral协议,比如 String、NSString。因此这个扩展可同时用于 String 和 NSString\NSMutableString。
  4. 打印 base 的内容。因为 base 有可能是 NSString,所以可以先转为 String 类型。

当然,我们还可以修改泛型约束的条件,让这个扩展(前缀)也可以应用到其它类型:

extension Int: AbcProtocol{} 
extension Abc where Base == Int {       
    func test2() {
        print("\(base)")                   
    }
}

这样就实现了我们的扩展前缀功能。现在,要调用扩展中的方法,就必须加上 abc 前缀了:

"ABC123456".abc.test()
10.abc.test2()

扩展 static 方法

如果需要扩展 static 方法,那么就需要进一步扩展 Abc 结构体,让它再增加一个静态的 abc 属性:

extension AbcProtocol {
    var abc: Abc<Self> {
        set {}               
        get { Abc(self) }    
    }
    static var abc: Abc<Self>.Type {      // 1
        set {}                          // 2
        get { Abc<Self>.self }           // 3

    }
}

  1. 定义一个 static 的计算属性,其类型是 Abc.self 的 Type。
  2. 必须,否则编译器报错。
  3. 返回 Abc.self 的类型(非实例)。同时将 self 传入到 base 属性,同时明确泛型的类型。

在 Abc 的扩展中定义 static 方法,然后调用 static 方法:

String.abc.test()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值