不要使用Runtime在分类中添加代理属性
2018-08-17 本文已影响6人
seasonZhu
最近因为封装的需要,我在Swift中的UITableView中添加了一个代理属性以便于我进行下拉与上拉的刷新的回调操作.
结果我发现,为其添加的代理属性导致了循环引用.
没错,就算你这个代理属性使用weak修饰,就算你在使用的过程怎么小心翼翼,这个代理的循环引用都是存在的.
为了验证其普遍性,我做了以下很没技术含量的代码测试,然后你就可以看到循环引用了
添加UIView代理属性的分类
import UIKit
private var delegateString = "UIViewRuntimeInterface"
// MARK: - 为UIView添加代理属性
extension UIView {
weak var delegate: UIViewRuntimeInterface? {
get {
return objc_getAssociatedObject(self, &delegateString) as? UIViewRuntimeInterface
}
set {
objc_setAssociatedObject(self, &delegateString, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
protocol UIViewRuntimeInterface: class {
func uiViewRuntimeInterfaceMethod()
}
ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 0, y: 200, width: UIScreen.main.bounds.width, height: 22))
button.setTitle("Push", for: .normal)
button.setTitleColor(UIColor.black, for: .normal)
button.addTarget(self, action: #selector(buttonAction(_ :)), for: .touchUpInside)
view.addSubview(button)
}
@objc private func buttonAction(_ button: UIButton) {
let secondVC = SecondController()
navigationController?.pushViewController(secondVC, animated: true)
}
}
SecondController
import UIKit
class SecondController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
let aView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
aView.backgroundColor = UIColor.lightGray
aView.center = view.center
aView.delegate = self
view.addSubview(aView)
}
deinit {
print("SecondController被销毁了")
}
}
extension SecondController: UIViewRuntimeInterface {
func uiViewRuntimeInterfaceMethod() {
print("哈哈哈")
}
}
我个人的理解是runtime对分类添加的属性就是永远都是strong类型.
同时我使用OC干了同样的事情,OC中在分类中添加代理属性,那么引用也会造成循环引用.
所以,不要使用Runtime在分类中添加代理属性,而是使用Runtime在分类中添加使用Block或者Callback进行回调,这样是不会造成循环引用的.
通过继承添加属性这个当然是可以的.