捕獲強弱的參考並保留週期
class MyClass {
func sayHi() { print("Hello") }
deinit { print("Goodbye") }
}
當閉包捕獲引用型別(類例項)時,預設情況下它包含一個強引用:
let closure: () -> Void
do {
let obj = MyClass()
// Captures a strong reference to `obj`: the object will be kept alive
// as long as the closure itself is alive.
closure = { obj.sayHi() }
closure() // The object is still alive; prints "Hello"
} // obj goes out of scope
closure() // The object is still alive; prints "Hello"
閉包的捕獲列表可用於指定弱引用或無主引用:
let closure: () -> Void
do {
let obj = MyClass()
// Captures a weak reference to `obj`: the closure will not keep the object alive;
// the object becomes optional inside the closure.
closure = { [weak obj] in obj?.sayHi() }
closure() // The object is still alive; prints "Hello"
} // obj goes out of scope and is deallocated; prints "Goodbye"
closure() // `obj` is nil from inside the closure; this does not print anything.
let closure: () -> Void
do {
let obj = MyClass()
// Captures an unowned reference to `obj`: the closure will not keep the object alive;
// the object is always assumed to be accessible while the closure is alive.
closure = { [unowned obj] in obj.sayHi() }
closure() // The object is still alive; prints "Hello"
} // obj goes out of scope and is deallocated; prints "Goodbye"
closure() // crash! obj is being accessed after it's deallocated.
有關更多資訊,請參閱“ 記憶體管理” 主題和 “Swift 程式語言” 的“ 自動引用計數” 部分。
保留週期
如果一個物件保持一個閉包,該閉包也保持對該物件的強引用,那麼這是一個保留週期 。除非迴圈被破壞,否則儲存物件和閉包的記憶體將被洩露(永不回收)。
class Game {
var score = 0
let controller: GCController
init(controller: GCController) {
self.controller = controller
// BAD: the block captures self strongly, but self holds the controller
// (and thus the block) strongly, which is a cycle.
self.controller.controllerPausedHandler = {
let curScore = self.score
print("Pause button pressed; current score: \(curScore)")
}
// SOLUTION: use `weak self` to break the cycle.
self.controller.controllerPausedHandler = { [weak self] in
guard let strongSelf = self else { return }
let curScore = strongSelf.score
print("Pause button pressed; current score: \(curScore)")
}
}
}