我在控制器中有一个类对象,然后我在这个对象中有一个闭包。 我将控制器的一个功能分配给对象的闭包,然后页面没有被删除。
我该如何解决这个问题?
import UIKit
class SecondViewController: UIViewController {
let test = TestObject()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
self.test.select = self.selectButton(index:)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.test.doSomethine()
}
func selectButton(index:Int){
print(index)
}
deinit {
print("deinit")
}
}
import UIKit
typealias selectBtnBlock = (_ index:Int)->()
class TestObject: NSObject {
var select:selectBtnBlock?
func doSomethine(){
self.select!(1)
}
}
答案 0 :(得分:3)
这是因为当您执行以下操作时,test
对象的选择关闭强烈会捕获您的SecondViewController
:
self.test.select = self.selectButton(index:)
我建议您通过Apple的Swift语言参考阅读弱弱类型。您遇到的“有趣现象”称为强参考周期。
基本上,由于Swift使用ARC作为其内存管理模型,因此至少有一个其他对象引用的任何对象都将保持活动状态,并且其内存不会被释放。
在您的情况下,test
已通过我提到的行捕获了其父SecondViewContoller
。这意味着你有以下情况:
SecondViewController -> (owns) test // since its a member of the class
test -> (strongly captures) SecondViewController // via the assignment
这会在两者之间产生强大的参考周期,并且不允许ARC解除分配。
当它(ARC)尝试释放test
时,知道SecondViewController
引用它,因此只有在父项也被释放时才能释放它。当它尝试释放SecondViewController
时,ARC知道test.select
闭包引用了该对象。
由于两者的引用计数都大于1,因此都不会被取消分配。
解决问题的一种方法是写:
self.test.select = {
[weak self] // weakly capture self, this prevents a ref cycle
(i:Int)->() in // a closure that accepts an Int
guard let s = self else { return } // check if self is not nil
s.selectButton(index: i) // finally invoke the required method
}
另一种方式,类似意图:
self.test.select = { [weak self] i in
self?.selectButton(index: i)
}
此上下文中的weak
关键字用于告诉Swift编译器我不想强烈引用我正在捕获的内容(在这种情况下为self
)。