swift面向协议编程(POP)之经典实例

1、实例说明及实现

使用委托模式实现。
协议最常见的用法莫过于进行代理传值。常用的场景有:controller中自定义了一个view,view中添加了一个button。点击自定义中的button去改变在controller上label的值。代码如下:

自定义ClickView.swift:

//
//  ClickView.swift
//  Demo
//
//  Created by 王树军 on 2018/7/30.
//  Copyright © 2018 王树军. All rights reserved.
//

import UIKit

/* 屏幕的宽 */
public let kSCREEN_WIDTH  = UIScreen.main.bounds.size.width
/* 屏幕的高 */
public let kSCREEN_HEIGHT  = UIScreen.main.bounds.size.height

@objc protocol ClickViewDelegate {
    func changeLabel(_ str: String)
}

class ClickView: UIView {

    var keywords: [String]?
    var buttons: [UIButton]?
    
    weak public var delegate: ClickViewDelegate?
    
    init(frame: CGRect, keywords: [String]) {
        super.init(frame: frame)
        self.keywords = keywords
        renderVier()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
    }
    
    private func renderVier() {
        buttons = keywords?.enumerated().map({ (index, key) -> UIButton in
            let buttonWidth = kSCREEN_WIDTH/CGFloat((keywords?.count)!)
            let button = UIButton.init(frame: CGRect.init(x: CGFloat(index)*buttonWidth, y: 0, width: buttonWidth, height: 50))
            button.setTitle(key, for: .normal)
            button.setTitleColor(UIColor.blue, for: .normal)
            button.backgroundColor = UIColor.gray
            button.tag = index
            button.addTarget(self, action: #selector(tapButton(sender:)), for: .touchUpInside)
            addSubview(button)
            return button
            
        })
    }
    
    @objc func tapButton(sender: UIButton) {
        delegate?.changeLabel(keywords![sender.tag])
    }
}

ViewController.swift

//
//  ViewController.swift
//  Demo
//
//  Created by 王树军 on 2018/7/30.
//  Copyright © 2018 王树军. All rights reserved.
//

import UIKit

class ViewController: UIViewController ,ClickViewDelegate{
    
    lazy var label: UILabel = {
        var label = UILabel(frame: CGRect.init(x: 50, y: 200, width: 100, height: 30))
        label.text = labelStr
        label.backgroundColor = UIColor.red
        return label
    }()
    
    var labelStr: String? {
        didSet {
            label.text = labelStr
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        view.addSubview(label)
        setupClickView()
    }
    
    func setupClickView() {
        let clickView =   ClickView(frame: CGRect.init(x: 0, y: 88, width: kSCREEN_WIDTH, height: 50), keywords: ["aa", "bb"])
        clickView.delegate = self
        view.addSubview(clickView)
    }
    
    func changeLabel(_ str: String) {
        labelStr = str
    }
}


2、注意事项

  • 1、在 ARC 中,对于一般的 delegate,我们会在声明中将其指定为 weak,在这个 delegate 实际的对象被释放的时候,会被重置回 nil。

  • 2、 Swift 的 protocol 是可以被除了 class 以外的其他类型遵守的,而对于像 struct 或是 enum 这样的类型,本身就不通过引用计数来管理内存,所以也不可能用 weak 这样的 ARC 的概念来进行修饰。
    两种解决方法:
    ①、使用@objc
    ②、声明类类型专属协议。通过添加 class 关键字来限制协议只能被类类型遵循,
    而结构体或枚举不能遵循该协议。class 关键字必须第一个出现在协议的继承列表中,在其他继承的协议之前
    protocol ClickViewDelegate : class

你可能感兴趣的:(swift面向协议编程(POP)之经典实例)