从 xx_ 前缀向 xx. 命名空间协议转变

栏目: Swift · 发布时间: 5年前

内容简介:最近在写新项目的时候,在一个下拉组件中看到了 .es 的语法,于是想到了很多的第三库如 Kingfisher, RxSwift 都使用了类似的 .kf, .rx 语法,从而引发了一段思考。首先说说这个语法出现的场景,通常自己写的类或者封装的组件都会自己加前缀,但是在系统方法扩展的时候官方在 OC 时代给到的推荐是因为是 RxSwift 的使用者,很早的时候记得当时的语法糖是

最近在写新项目的时候,在一个下拉组件中看到了 .es 的语法,于是想到了很多的第三库如 Kingfisher, RxSwift 都使用了类似的 .kf, .rx 语法,从而引发了一段思考。

首先说说这个语法出现的场景,通常自己写的类或者封装的组件都会自己加前缀,但是在系统方法扩展的时候官方在 OC 时代给到的推荐是 前缀_ 的方式,在 Swift 语言出现后一段时间,开发者保留了这样的写法,但是因为 Swift 语言的发展,以及语言的特性,面向协议编程 (Protocol Oriented Programming,以下简称 POP),从而引出下面的写法。

.rx

因为是 RxSwift 的使用者,很早的时候记得当时的语法糖是 rx_ , 这个是非常重度的 OC 语法推荐写法,在自己对系统方法进行扩展的时候需要加上前缀,方式方法名称重复。但是我们发现后续版本中这个语法糖做出了改变,大家可以参考 RxSwift 的这个帖子 [RxCocoa] Move from rx_ prefix to a rx. proxy (for Swift 3 update ?) ,这篇帖子的标题解释了一个很重要的概念,就是 rx_ 向 rx. 转变的时候是由带前缀的方法名称向协议去转变,通过拥有对象的协议去实现扩展方法。

具体实现

鉴于上面 RxSwift Issue 时间比较久远,这边提供几个近期的完整实现:

实现 Base

实现一个 Base 的 Struct/ Class,推荐 Struct。

这个 Struct 将真实的对象包裹起来,作为一个泛型结构体,不做任何实际操作。

public struct KingfisherWrapper<Base>{
    public let base: Base
    public init(_ base: Base) {
        self.base = base
    }
}

实现 Protocol 和 .kf 方法

定一个 protocol,不实现任何变量方法声明,防止其他的 protocol 继承会修改到变量方法的实现。

然后实现 protocol 的 extension,提供一个 default implementation,这边其实就是实现了一个 kf 的属性,这个属性是 KingfisherWrapper 的实例, public var kf: KingfisherWrapper<Self> Self 用在协议里面,代表的是遵守协议的对象(类/结构体/枚举)类型,即 Base 类型,根据 Base 类的不同,实现对应类里面的方法。

这样,就相当于实现了 kf 的命名空间。

public protocol KingfisherCompatible:AnyObject{ }

extension KingfisherCompatible{
    /// Gets a namespace holder for Kingfisher compatible types.
    public var kf: KingfisherWrapper<Self> {
        get { return KingfisherWrapper(self) }
        set { }
    }
}

将 Protocol 加载到所需的 Base 类并通过Extension + where Base 实现 Base 类的特定代码

将我们需要扩展的系统类遵循 protocol,这样对应的 KingfisherWrapper 对象就可以实现对应的系统类里面的方法。

在实现方法里面有个特别要注意的点,所以 UIImageView 的属性,即可以用 self. 调用的属性都需要变成 base. ,因为这边的调用 .kf 的时候每次返回的都是全新的 KingfisherWrapper 实例对象,并不是调用本身对象。

因为

extension UIImage:KingfisherCompatible{ }

extension KingfisherwhereBase:UIImageView{
    public func setImage(image: UIImage) {
        base.image = image
    }
}

使用场景

从上面的分析中来看,这样通过协议命名空间方法实现的 extension 看上去会跟优雅,也能过解决在项目中 manually 方式引入第三方库的时候,出现同名的扩展引起的冲突。但是在扩展的时候我同样发现一个问题,对于 initializers methods 是没办法使用命名空间去扩展的,我们只能对应的给一个 func 返回设置好的 Color 作为返回值。

convenience init(hex: Int, alpha: CGFloat = 1) {
        var t_alpha = alpha
        if t_alpha < 0 { t_alpha = 0 }
        if t_alpha > 1 { t_alpha = 1 }

        let red = (hex >> 16) & 0xff
        let green = (hex >> 8) & 0xff
        let blue = hex & 0xff
        self.init(red: red, green: green, blue: blue, alpha: t_alpha)
    }

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Lean Startup

The Lean Startup

Eric Ries / Crown Business / 2011-9-13 / USD 26.00

更多中文介绍:http://huing.com Most startups fail. But many of those failures are preventable. The Lean Startup is a new approach being adopted across the globe, chan ging the way companies are built and ......一起来看看 《The Lean Startup》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

html转js在线工具
html转js在线工具

html转js在线工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具