从 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)
    }

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

查看所有标签

猜你喜欢:

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

深入理解Java虚拟机(第2版)

深入理解Java虚拟机(第2版)

周志明 / 机械工业出版社 / 2013-9-1 / 79.00元

《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》内容简介:第1版两年内印刷近10次,4家网上书店的评论近4?000条,98%以上的评论全部为5星级的好评,是整个Java图书领域公认的经典著作和超级畅销书,繁体版在台湾也十分受欢迎。第2版在第1版的基础上做了很大的改进:根据最新的JDK 1.7对全书内容进行了全面的升级和补充;增加了大量处理各种常见JVM问题的技巧和最佳实践;增加了若干......一起来看看 《深入理解Java虚拟机(第2版)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码