簡介
面向協(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,如有需要可自取