通常我们为系统控件添加扩展时,为了快速定位到我们写的扩展属性,且独立于其他扩展,防止冲突。代码提示属性过多。我们会添加为扩展属性添加命名空间
如: userTextField 是在某个类中定义的 UITextField,假如我们给 UITextField 扩展一个 get 属性
extension UITextField {
var isValid: Bool { self.text?.count ?? 0 > 0 }
}
调用时候是 self.userTextField.isValid
,但是我们期望实现的效果是 self.userTextField.vs.isValid
,试着写一下
extension UITextField {
struct VS {}
var vs: VS.Type { VS.self }
}
extension UITextField.VS {
var isValid: Bool { self.text?.count ?? 0 > 0 }
}
text 无法通过 self 去获取,因为此时调用的实例是 UITextField.VS吗, 因此需要定义一个属性来获取原来的对象 userTextField
这里用 self.base 来获取原来的对象 userTextField
extension UITextField {
struct VS {
let base: UITextField
init(_ base: UITextField) {
self.base = base
}
}
var vs: VS { VS.init(self) }
}
extension UITextField.VS {
var isValid: Bool { self.base.text?.count ?? 0 > 0 }
}
这样可以初步实现我们的效果,但是如果其他系统控件也需要添加对应的扩展,那需要重复定义 struct VS {}
我们可以设想把 var vs: VS { VS.init(self) }
写成协议
struct VS<Base> {
let base: Base
init(_ base: Base) {
self.base = base
}
}
protocol VSProtocol {
var vs: VS<Self> { get }
}
extension VSProtocol {
var vs: VS<Self> { VS<Self>.init(self) }
}
extension NSObject: VSProtocol { }
这样写会发生报错
Protocol 'VSProtocol' requirement 'vs' cannot be satisfied by a non-final class ('NSObject') because it uses 'Self' in a non-parameter, non-result type position`
需要添加别名 associatedtype Base
struct VS<Base> {
let base: Base
init(_ base: Base) {
self.base = base
}
}
protocol VSProtocol {
associatedtype Base
var vs: VS<Base> { get }
}
extension VSProtocol {
var vs: VS<Self> { VS<Self>.init(self) }
}
extension NSObject: VSProtocol { }
最后加上扩展,搞定
extension VS where Base: UITextField {
var isValid: Bool { self.base.text?.count ?? 0 > 0 }
}
以上对 RxSwift 代码进行参考分析
网友评论