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

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

内容简介:最近在写新项目的时候,在一个下拉组件中看到了 .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)
    }

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

查看所有标签

猜你喜欢:

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

高等应用数学问题的MATLAB求解

高等应用数学问题的MATLAB求解

薛定宇、陈阳泉 / 清华大学出版社 / 2008-10 / 49.00元

薛定宇和陈阳泉编著的《高等应用数学问题的MATLAB求解》首先介绍了MATLAB语言程序设计的基本内容,在此基础上系统介绍了各个应用数学领域的问题求解,如基于MATLAB的微积分问题、线性代数问题的计算机求解、积分变换和复变函数问题、非线性方程与最优化问题、常微分方程与偏微分方程问题、数据插值与函数逼近问题、概率论与数理统计问题的解析解和数值解法等,还介绍了较新的非传统方法,如模糊逻辑与模糊推理、......一起来看看 《高等应用数学问题的MATLAB求解》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换