2017-12-24 3 views
4

Gibt es so etwas? Gibt es einen Unterschied zwischen den beiden unten? Ist einer mehr "korrekt" als der andere?Optimieren der Aufnahmelisten

Alle Objekte sind Eigenschaften von self (sagen wir ein View-Controller) und haben die gleiche Lebensdauer wie self. Wir können ein Objekt mit einer kürzeren Lebensdauer als self einführen, das wäre weak, aber die gleiche Frage gilt.

objectOne.doSomething { [unowned self] in 
    self.objectTwo.finish() 
    self.tableView.reloadData() 
    // self.someDelegate?.didFinishSomething() 
} 

vs

objectOne.doSomething { 
    [unowned objectTwo = self.objectTwo, 
    unowned tableView = self.tableView 
    // weak someDelegate = self.delegate 
    ] in 
    objectTwo.finish() 
    tableView.reloadData() 
    // someDelegate?.didFinishSomething() 
} 

hat Apple dieses Beispiel in their docs:

lazy var someClosure:() -> String = { 
    [unowned self, weak delegate = self.delegate!] in 
    // closure body goes here 

    delegate?.doSomething() 
} 

In diesem Fall delegate kann eine kürzere Lebensdauer haben als self, aber warum es nicht so benutzen?

lazy var someClosure:() -> String = { 
    [unowned self] in 
    // closure body goes here 

    self.delegate?.doSomething() 
} 

Antwort

1

Ja, es gibt einen wichtigen Unterschied. Im Fall der Apple-docs, Sie den Code Alternative vorgestellt:

lazy var someClosure:() -> String = { 
    [unowned self] in 
    // closure body goes here 

    self.delegate?.doSomething() 
} 

die aktuellendelegate auf self nachschlägt, wenn der Verschluss läuft.

in Apple-Beispiel Version:

lazy var someClosure:() -> String = { 
    [unowned self, weak delegate = self.delegate!] in 
    // closure body goes here 

    delegate?.doSomething() 
} 

die schwachen delegate var in der Aufnahmeliste sind Kopieren die delegate Zeiger auf self, die nicht der Ausführung zum Zeitpunkt der Schließung Erklärung besteht. Wenn sich also der Wert self.delegate nach der Deklaration ändert und zum Zeitpunkt des Abschlusses anders ist, hat die Apple-Version des Closures einen Nulldelegaten (vermutlich, da der Verweis auf den alten Delegaten schwach war) und tut nichts.

Als allgemeine Regel gilt, dass beim Kopieren von Werten oder Referenzen in Erfassungslisten ([someIdentifier = someProperty]) die Werte oder Referenzen verwendet werden, die zum Zeitpunkt der Definition des Abschlusses existieren. Wenn Sie in der Erfassungsliste ein schwaches oder nicht verwendetes Selbst deklarieren ([weak self]) und dann auf die Eigenschaften dieser schwachen Referenz ({ self?.someProperty }) zugreifen, werden die Werte der Eigenschaften wie bei der Ausführung des Abschlusses abgerufen.

+0

Das macht sehr viel Sinn, danke! Dies sollte dann ein Grund für das Verhalten in meiner Antwort sein: Die 'faule' Init wird ausgelöst, wenn die Schließung erklärt wird, kombiniert mit der Tatsache, dass sie sich in einem anderen Thread befindet als andere Trigger. – Roland

0

Eines der Probleme, dass [unowned objectOne = self.objectOne] verursachen könnte mit lazy var UIViews und Rennbedingungen: Wenn Sie nicht vorsichtig sind und die lazy init wird aus verschiedenen Threads aufgerufen, zwei Instanzen könnten am Ende erstellt werden. Wenn Ihr Anruf superview.addSubview(objectOne) in der lazy Init ist, werden beide Instanzen zu superview hinzugefügt, und wird auf eine der beiden Instanzen verweisen.