任何人都可以解释为什么这不泄漏?
我在self
内捕获closure
所以我会有两个强指针指向对方,因此,不应该为Person对象调用deinit
消息
首先,这是我的班级人:
class Person {
var name: String
init(name: String) { self.name = name }
deinit { print("\(name) is being deinitialized") }
}
这是我的 ViewController的实现:
class ViewController: UIViewController {
var john:Person?
func callClosureFunction( closure:(name:Bool) -> () ) {
closure(name: true)
}
override func viewDidLoad() {
super.viewDidLoad()
john = Person(name:"John")
self.callClosureFunction { (name) in
self.john?.name = "John Appleseed"
self.john = nil
// xcode prints - John Appleseed is being deinitialized
}
}
}
我希望通过以下方式解决问题:
self.callClosureFunction { [weak self] (name) in ...
但这甚至没有必要。为什么呢?
答案 0 :(得分:4)
由于视图控制器不保留闭包,因此没有循环引用。如果你写了这个:
class ViewController: UIViewController {
var john:Person?
var closure:(Bool)->()?
func callClosureFunction( closure:((name:Bool) -> ())? ) {
closure?(name: true)
}
override func viewDidLoad() {
super.viewDidLoad()
john = Person(name:"John")
closure = { (name) in
self.john?.name = "John Appleseed"
// Because this closure will never be released, the instance of Person will never deinit either
}
self.callClosureFunction(closure)
}
}
然后视图控制器将保留闭包,闭包将通过其对self
的引用保留视图控制器。因此,两者都不会被释放,如果您没有明确设置self.john = nil
(您在原始示例中所做的那样),那么Person
实例将永远不会被deninit
调用。
在没有必要的情况下,在闭包中不恰当地使用弱self
是很常见的(这实际上可能导致一些模糊的错误)。要记住的关键规则是,弱引用通常不是ARC下的默认引用。 Strong应该是默认的,除非它会导致保留周期,在这种情况下,weak应该仅用于打破循环引用。闭包相同:强self
应该是默认值,除非 self
在这种情况下也有对闭包本身的强引用。
答案 1 :(得分:0)
您正在抓取指向self
的{{1}},但您想知道ViewController
个实例。
Person
实际上不是循环引用的,因此当你在闭包结束时将它设置为nil时,它会被释放并释放得很好。
为Person
实施deinit
,看看它是如何运作的。
答案 2 :(得分:0)
我在一个闭包中捕获self,所以我会有两个强指针指向对方,因此,不应该为Person对象调用deinit消息。
不,你有一个强大的指针,从闭包到self
。从闭包到self
没有循环引用。因此,您有directed acylic graph,这对ARC来说没有问题。
但是,从一开始,您的实验就存在缺陷。即使已捕获闭包,John Appleseed
Person
对象仍会deinit
。此对象的生命周期完全取决于john
的{{1}}引用。当您将该引用设置为ViewController
时,您将删除对nil
对象的最后一次引用,从而将其取消初始化。