RxSwift - 为自定义 get 属性添加命名空间

2022-07-14  本文已影响0人  ienos

通常我们为系统控件添加扩展时,为了快速定位到我们写的扩展属性,且独立于其他扩展,防止冲突。代码提示属性过多。我们会添加为扩展属性添加命名空间

如: 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 代码进行参考分析

上一篇 下一篇

猜你喜欢

热点阅读