Swift面向协议编程

简介

面向协议编程的思想在swift中处处可见,比如swift常用的数据类型String, Array, Dictonary,等等都是通过尊村不同的协议来实现对应的功能,今天我主要是想讨论下在实际开发中怎么更好的利用面向协议编程

xib 加载 UIView

平时开发中难免会遇到使用xib创建视图的时候,加载xib视图的代码又有点冗长,这个时候使用协议就很方便

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
    }
}

我们可以声明一个协议,然后在extension里添加一个默认实现,当我们需要加载一个xib视图的时候,只需要让这个xib视图遵守这个协议就可以了

class ShakeView: UIView, NibLoadable, Shakeable {

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

然后我们在创建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

平时开发UITableView用的是比较多的,tableview的注册cell的代码我们也可以使用协议实现更简便的实现

/**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.Type) where T: ReusableView, T: NibLoadable {
        let Nib = UINib(nibName: T.NibName, bundle: nil)
        register(Nib, forCellReuseIdentifier: T.reuseIdentifier)
    }
    
    func register(_ : T.Type) where T: ReusableView {
        register(T.self, forCellReuseIdentifier: T.reuseIdentifier)
    }
}

这样我们在注册cell的时候就可以写出比较简洁的代码

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

另外我们也可以用协议让创建和复用cell更简洁

/**UITableView create cell protocol*/
extension UITableView {
    func dequeueReusableCell(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
    }

实现抖动view

网上很多人都会拿这个举例面向协议,个人觉得确实很贴切,当你想要实现一个视图的抖动确实有很多方法,但是使用协议确实很方便,只要视图遵守协议,就具有对应功能,,想去除这个功能的时候就取消对协议的遵守就可以了,对代码的侵入性也比较小,这样对代码的维护和扩展,还有可读性都很好,就像swift里的Array遵守了Equatable、Collection等不同的协议来实现不同的功能

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()
    }
}

这里是相关Demo,如有需要可自取

参考

Swift 面向协议编程
刀真枪 面向协议编程

你可能感兴趣的:(Swift面向协议编程)