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