最近看到一篇文章,实现swift中UIView的链式调用的简单封装。
其中谈到为了防止自己在extension中声明的方法与未来UIView中新推出的方法重名或者冲突,使用了命名空间形式扩展的实现。来达到如下的效果
let label = UILabel()
.hand.adhere(toSuperView: view)
.hand.layout { (make) in
make.top.equalToSuperview().offset(80)
make.centerX.equalToSuperview()
}
.hand.config(labelConfiger)
其中每次具体方法调用之前都需要调用hand就是一种命名空间形式的扩展。
然后源代码如下:
public protocol NamespaceWrappable {
associatedtype WrapperType
var hand: WrapperType { get }
static var hand: WrapperType.Type { get }
}
public extension NamespaceWrappable {
var hand: NamespaceWrapper<Self> {
return NamespaceWrapper(value: self)
}
static var hand: NamespaceWrapper<Self>.Type {
return NamespaceWrapper.self
}
}
public struct NamespaceWrapper<T> {
public let wrappedValue: T
public init(value: T) {
self.wrappedValue = value
}
}
最后附上命名空间形式下对UIView调用方法的扩展
import UIKit
import SnapKit
extension UIView: NamespaceWrappable { }
extension NamespaceWrapper where T: UIView {
public func adhere(toSuperView: UIView) -> T {
toSuperView.addSubview(wrappedValue)
return wrappedValue
}
@discardableResult
public func layout(snapKitMaker: (ConstraintMaker) -> Void) -> T {
wrappedValue.snp.makeConstraints { (make) in
snapKitMaker(make)
}
return wrappedValue
}
@discardableResult
public func config(_ config: (T) -> Void) -> T {
config(wrappedValue)
return wrappedValue
}
}
本质上,就是把类似于adhere
,layout
,config
这样的方法从UIView的名下挪到NamespaceWrapper下,让UIView能够获取NamespaceWrapper的实例来进行间接调用。