Swift面向協(xié)議編程

簡介

面向協(xié)議編程的思想在swift中處處可見,比如swift常用的數(shù)據(jù)類型String, Array, Dictonary,等等都是通過尊村不同的協(xié)議來實現(xiàn)對應(yīng)的功能,今天我主要是想討論下在實際開發(fā)中怎么更好的利用面向協(xié)議編程

xib 加載 UIView

平時開發(fā)中難免會遇到使用xib創(chuàng)建視圖的時候,加載xib視圖的代碼又有點冗長,這個時候使用協(xié)議就很方便

protocol NibLoadable: class {}

extension NibLoadable where Self: UIView {
    static var NibName: String {
        return String.init(describing: self)
    }
    static func loadViewFromNib() -> Self {
        return Bundle.main.loadNibNamed("\(self)", owner: nil, options: nil)?.last as! Self
    }
}

我們可以聲明一個協(xié)議,然后在extension里添加一個默認實現(xiàn),當(dāng)我們需要加載一個xib視圖的時候,只需要讓這個xib視圖遵守這個協(xié)議就可以了

class ShakeView: UIView, NibLoadable, Shakeable {

    @IBOutlet weak var centerLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
}

然后我們在創(chuàng)建xib視圖的時候就可以直接使用loadViewFromNib方法

lazy var shakeView: ShakeView = {
        let v = ShakeView.loadViewFromNib()
        v.frame = CGRect.init(x: 40, y: 100, width: 200, height: 80)
        return v
    }()

UITableView注冊Cell

平時開發(fā)UITableView用的是比較多的,tableview的注冊cell的代碼我們也可以使用協(xié)議實現(xiàn)更簡便的實現(xiàn)

/**load nib protocol*/
protocol NibLoadable: class {}

extension NibLoadable where Self: UIView {
    static var NibName: String {
        return String.init(describing: self)
    }
    static func loadViewFromNib() -> Self {
        return Bundle.main.loadNibNamed("\(self)", owner: nil, options: nil)?.last as! Self
    }
}


/** reuse view protocol*/
protocol ReusableView: class {}

extension ReusableView where Self: UIView {
    static var reuseIdentifier: String {
        return String.init(describing: self)
    }
}

/**UITableView regist cell protocol*/
extension UITableView {
    func register<T: UITableViewCell>(_: T.Type) where T: ReusableView, T: NibLoadable {
        let Nib = UINib(nibName: T.NibName, bundle: nil)
        register(Nib, forCellReuseIdentifier: T.reuseIdentifier)
    }
    
    func register<T: UITableViewCell>(_ : T.Type) where T: ReusableView {
        register(T.self, forCellReuseIdentifier: T.reuseIdentifier)
    }
}

這樣我們在注冊cell的時候就可以寫出比較簡潔的代碼

//        tableView.register(MMTableViewCell.self)
        tableView.register(MMNibTableViewCell.self)

另外我們也可以用協(xié)議讓創(chuàng)建和復(fù)用cell更簡潔

/**UITableView create cell protocol*/
extension UITableView {
    func dequeueReusableCell<T: UITableViewCell>(forIndexPath indexPath: IndexPath) -> T where T: ReusableView {
        guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath as IndexPath) as? T else {
            fatalError("Could not dequeue cell with identifier: \(T.reuseIdentifier)")
        }
        return cell
      }
}

使用的時候

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as MMNibTableViewCell
        cell.textLabel?.text = "the nib row \(indexPath.row)"
        return cell
    }

實現(xiàn)抖動view

網(wǎng)上很多人都會拿這個舉例面向協(xié)議,個人覺得確實很貼切,當(dāng)你想要實現(xiàn)一個視圖的抖動確實有很多方法,但是使用協(xié)議確實很方便,只要視圖遵守協(xié)議,就具有對應(yīng)功能,,想去除這個功能的時候就取消對協(xié)議的遵守就可以了,對代碼的侵入性也比較小,這樣對代碼的維護和擴展,還有可讀性都很好,就像swift里的Array遵守了Equatable、Collection等不同的協(xié)議來實現(xiàn)不同的功能

protocol Shakeable {}

extension Shakeable where Self : UIView {
    func shake() {
        let animation = CABasicAnimation(keyPath: "position")
        animation.duration = 0.05
        animation.repeatCount = 5
        animation.autoreverses = true
        animation.fromValue = CGPoint.init(x: self.center.x - 4.0, y: self.center.y)
        animation.toValue = CGPoint.init(x: self.center.x + 4.0, y: self.center.y)
        layer.add(animation, forKey: "position")
    }
}

使用

import UIKit

class ShakeView: UIView, NibLoadable, Shakeable {

    @IBOutlet weak var centerLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
}



class ViewController: UIViewController {
    
    //MARK: - lazy var
    lazy var shakeView: ShakeView = {
        let v = ShakeView.loadViewFromNib()
        v.frame = CGRect.init(x: 40, y: 100, width: 200, height: 80)
        return v
    }()

// MARK: - Action
    @objc func btnAction() {
        shakeView.shake()
    }
}

這里是相關(guān)Demo,如有需要可自取

參考

Swift 面向協(xié)議編程
刀真槍 面向協(xié)議編程

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容