Swift Language Cattura, riferimenti forti / deboli e conserva i cicli

Esempio

class MyClass {
    func sayHi() { print("Hello") }
    deinit { print("Goodbye") }
}

Quando una chiusura acquisisce un tipo di riferimento (un'istanza di classe), mantiene un riferimento forte per impostazione predefinita:

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"

L' elenco di cattura della chiusura può essere utilizzato per specificare un riferimento debole o non associato:

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.

Per ulteriori informazioni, consultare l'argomento Gestione della memoria e la sezione Conteggio riferimento automatico di Swift Programming Language.

Conservare i cicli

Se un oggetto tiene su una chiusura, che contiene anche un forte riferimento all'oggetto, questo è un ciclo di conservazione . A meno che il ciclo non sia interrotto, la memoria che memorizza l'oggetto e la chiusura sarà trapelata (mai bonificata).

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)")
        }
    }
}