2017-09-06 4 views
1

Jetzt, wenn eine Schließung auf sich selbst innerhalb ihres Körpers verweist, fängt die Schließung selbst ein, was bedeutet, dass sie eine starke Referenz auf die HTMLElement-Instanz hält (siehe unten). Ein starker Referenzzyklus wird zwischen den beiden erstellt. Dies bedeutet, dass die Instanz nicht deinitialisiert (wie unten gezeigt); wenn ich jedoch versucht habe, self durch die Überschrift (die Instanz) zu ersetzen, hat die Deinitialisierung funktioniert, was bedeutet, dass ein starker Referenzzyklus nicht existierte. Mein Verständnis ist, dass der Kurs in diesem Fall dasselbe ist wie das Selbst, da das Selbst die Instanz selbst ist. Warum also wurde die Instanz deinitialisiert, als ich sie durch die Instanz "Überschrift" ersetzt habe?Deinitialisierung, Selbst und Verschlüsse.

class HTMLElement { 

let name: String 
let text: String? 

lazy var asHTML:() -> String = { 
    let defaultText = "some default text" 
    return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>" 
} 
init(name: String, text: String? = nil) { 
    self.name = name 
    self.text = text 
} 

deinit { 
    print("\(name) is being deinitialized") 
} 

} 
var heading = HTMLElement(name: "h1") 
let defaultText = "some default text" 

print(heading.asHTML()) 
// Prints "<h1>some default text</h1>” 
heading = HTMLElement(name: "h4") 

Ausgang:

<h1> some default text </h1> 
h1 is being deinitialized 

Nun, wenn der Verschluss ersetzt wurde, wie folgt:

lazy var asHTML:() -> String = { 
let defaultText = "some default text" 
return "<\(self.name)>\(self.text ?? defaultText)</\(self.name)>" 
} 

die Ausgabe wäre:

< h1> einige Standardtext </h1 >

+0

keine doppelten mir scheinen. Es geht nicht um Lazy Close vs String Variable. – algrid

+0

Dieser Code zeigt, wie ARC funktioniert: Wenn Sie in einer Closure auf "self" verweisen, behält ARC das Objekt für Sie bei, um zu verhindern, dass es aufgehoben wird, sodass Sie beim Aufruf dieser Closure keine Probleme bekommen. Aber wenn Sie sich auf eine globale Variable beziehen, hat es keinen Sinn, ein Objekt zusätzlich beizubehalten - diese Variable wird immer für Sie verfügbar sein. – algrid

Antwort

1

Der korrekte Weg, einen starken Referenzzyklus mit einem Verschluss zu vermeiden, besteht darin, self entweder als unowned oder weak, z.

class HTMLElement { 

    let name: String 
    let text: String? 

    lazy var asHTML:() -> String = { [unowned self] in 
     let defaultText = "some default text" 
     return "<\(self.name)>\(self.text ?? defaultText)</\(self.name)>" 
    } 

    init(name: String, text: String? = nil) { 
     self.name = name 
     self.text = text 
    } 

    deinit { 
     print("\(name) is being deinitialized") 
    } 

} 

Es stellt sich die Frage, warum Sie eine Funktion verwenden, nicht nur

func asHTML() -> String { 
    let defaultText = "some default text" 
    return "<\(name)>\(text ?? defaultText)</\(name)>" 
} 

oder berechnete Eigenschaft:

var asHTML: String { 
    let defaultText = "some default text" 
    return "<\(name)>\(text ?? defaultText)</\(name)>" 
}