姜某 發表於 2022-9-14 15:01:18

Swift使用SnapKit模仿Kingfisher第三方扩展优化

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>正文</li><ul class="second_class_ul"><li>SnapKit扩展方式简要思考</li><li>Kingfisher扩展方式简要思考</li><li>自行模仿尝试</li></ul><li>最后</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>正文</h2>
<p>我们平时用<code>swift</code>写第三方扩展(OC中的分类)时,可能会直接就往扩展里面写方法,简单又方便,然而当我们看一些常用你的三方(例如:<code>Kingfisher、SnapKit</code>)等,都会用一个简单的参数引出(例如:<code>kf</code>、<code>snp</code>),下面来探索一下怎么用的,然后在总结其优缺点</p>
<p class="maodian"></p><h3>SnapKit扩展方式简要思考</h3>
<p>以 <code>SnapKit</code>为例,使用如下,发现引入了 <code>snp</code></p>
<div class="jb51code"><pre class="brush:js;">var iv = UIImageView();
iv.snp.makeConstraints { make in
}
</pre></div>
<p>中间变量 <code>snp</code> 如下所示,<code>ConstraintView</code>是统一不同平台的重命名(别名)</p>
<div class="jb51code"><pre class="brush:java;">public extension ConstraintView {
    var snp: ConstraintViewDSL {
      return ConstraintViewDSL(view: self)
    }
}
</pre></div>
<p>其以前版本也是直接将 <code>left</code> 等加上前缀 <code>snp_</code>,直接调用,而加入前缀我想大家一眼就看出来目的了,没错避免与其他扩展重名,现在也已经改成了引入<code>snp</code>的方式,来间接调用,实际逻辑都通过 <code>snp</code> 来调用,个人猜测也是借鉴了主流的应用来更新的,调用时,至少分类 API 整洁了</p>
<p>优缺点:</p>
<ul><li>1、引入中间变量 <code>snp</code> 之后,首先感觉到的就是,我们的分类在调用的时候,明显没有那么多杂乱的方法了(这种方式OC其实也可以借鉴)</li><li>2、另外也可以取消了<code>前缀</code>,减少了代码量,并且当与其他类出现重名的时候,只需要替换 <code>snp</code> 的变量名字即可,不需要替换<code>全部</code>方法,减少了命名阻碍</li><li>3、不同三方之间通过引入该参数,让我们的调用模块标识更明显,功能模块也更清晰,可维护性更强</li></ul>
<p class="maodian"></p><h3>Kingfisher扩展方式简要思考</h3>
<p>以 <code>Kingfisher</code>为例,使用如下,发现引入了 <code>kf</code></p>
<div class="jb51code"><pre class="brush:js;">var iv = UIImageView();
iv.kf.setImage(with: URL(string: "http://www.baidu.com"))
</pre></div>
<p>另外其在使用过程中,通过充分利用 <code>swift</code> 特性,比 <code>SnapKit</code> 使用上更优雅高效一些</p>
<div class="jb51code"><pre class="brush:java;">//声明一个基础协议,必须为 AnyObject 类型,可用于后续给基础类添加协议
public protocol KingfisherCompatible: AnyObject { }
//扩展实现该基础协议,以便于方便让我们的组件能够直接通过 .kf 直接调用里面的方法
//此 kf 和 snap 类似,只不过添加了一个泛型,用于不同类之间进行扩展限制
extension KingfisherCompatible {
    public var kf: KingfisherWrapper&lt;Self&gt; {
      get { return KingfisherWrapper(self) }
      set { }
    }
}
//通过泛型顶一个一个基础类,通过该基础类可以获取我们被扩展的组件
//且通过该基础类的泛型,可以分别给不同类型添加不同扩展方法
public struct KingfisherWrapper&lt;Base&gt; {
    public let base: Base
    public init(_ base: Base) {
      self.base = base
    }
}
//当遵循协议的类为 UIImage 的时候,为其扩展方法
extension KingfisherWrapper where Base: KFCrossPlatformImage {
    ...
}
//当遵循协议的类为 KFCrossPlatformImageView 的时候,为其扩展方法
extension KingfisherWrapper where Base: KFCrossPlatformImageView {
    ...
}
...
//上面仅仅是定义了一个扩展后可以使用的协议,并未应用到我们的基础组件中
//因此只需要给基础组件添加扩展,遵循我们的协议即可
extension KFCrossPlatformImageView: KingfisherCompatible { }
</pre></div>
<p>没见到名字的View 是为了不同平台统一名字起的别名,如下所示(打消疑虑专用)</p>
<div class="jb51code"><pre class="brush:js;">#if os(iOS) || os(tvOS)
    public typealias ConstraintView = UIView
#else
    public typealias ConstraintView = NSView
#endif
</pre></div>
<p>优缺点:</p>
<ul><li>1、引入中间变量 <code>kf</code> 之后,首先感觉到的就是,我们的分类在调用的时候,明显没有那么多杂乱的方法了(这种方式OC其实也可以借鉴)</li><li>2、另外也可以取消了前缀,减少了代码量,并且当与其他类出现重名的时候,只需要替换 <code>kf</code> 的变量名字即可,不需要替换全部方法,减少了命名阻碍</li><li>3、不同三方之间通过引入该参数,让我们的调用模块标识更明显,功能模块也更清晰,可维护性更强</li><li>4、引入协议和泛型,通过协议统一引入同一个中间变量,通过泛型给不同的分类扩展出不同的方法,减少无效方法和代码等,结构更清晰,某种角度上,其为进阶版的扩展方式</li></ul>
<p class="maodian"></p><h3>自行模仿尝试</h3>
<div class="jb51code"><pre class="brush:java;">public protocol MarshalTest: AnyObject {}
struct Wrapper&lt;T&gt;{
    public let base: T
    init(_ base: T) {
      self.base = base
    }
}
extension MarshalTest {
    var ml: Wrapper&lt;Self&gt; {
      get { Wrapper(self) }
      set { }
    }
}
extension UIImageView : MarshalTest {}
extension Wrapper where T: UIImageView {
    func setImg() {
    }
}
extension Wrapper where T: UIView {
    func setBkg() {
    }
}
class ViewController: UIViewController {
    override func viewDidLoad() {
      var iv2 = UIImageView()
      iv2.ml.setImg()
    }
}
</pre></div>
<p>这就测试成功了,我们模仿时,就可以参考这个写</p>
<p class="maodian"></p><h2>最后</h2>
<p>当我们自己为默认组件扩展内容时,如果只扩展一个类和功能,可以像 <code>snp</code> 一样,直接引入中间变量扩展即可,如果我们的扩展了多个分类,而隶属于一个模块,那么可以模仿 <code>Kingfisher</code>,让我们的功能更清晰</p>
<p>以上就是Swift SnapKit模仿Kingfisher第三方扩展优化示例的详细内容,更多关于SnapKit第三方扩展的资料请关注琼殿技术社区其它相关文章!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>swift中可选值?和!使用的方法示例</li><li>Swift中非可选的可选值类型处理方法详解</li><li>Swift Error重构优化详解</li><li>SwiftUI List在MacOS中的性能优化示例</li><li>Swift中图片资源使用流程的优化方法详解</li><li>Swift可选值优化示例详解</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Swift使用SnapKit模仿Kingfisher第三方扩展优化