3

ich wie folgtdie Referenz auf einen starken innerhalb des Verschlusses, Speicherverwaltung konvertieren, schnell

class Sample { 
     deinit { 
      print("Destroying Sample") 
     } 

     func additionOf(a: Int, b:Int) { 
      print("Addition is \(a + b)") 
     } 

     func closure() {     
      dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in 
      self?.additionOf(3, b: 3) 
      usleep(500)     
      self?.additionOf(3, b: 5) 
      } 
     } 
    } 

Später irgendwann den behalten Zyklus in Schließung bin experimentieren, ich tue

var sample : Sample? = Sample() 
sample?.closure() 

dispatch_async(dispatch_get_global_queue(0, 0)) { 
    usleep(100) 
    sample = nil 
} 

wird der Ausgang

Addition is 6 
Destroying Sample 

sein Dies ist verständlich, weil self nil out bevor Sie self?.additionOf(3, b:5)

Wenn ich eine Änderung innerhalb des Verschlusses gemacht durch eine andere Variable zu schaffen, die diesmal

dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in 
    guard let strongSelf = self else { return } 
    strongSelf.additionOf(3, b: 3) 
    usleep(500) 
    strongSelf.additionOf(3, b: 5) 
} 
wie folgt

zu [weak self] verweist, ist der Ausgang

Addition is 6 
Addition is 8 
Destroying C 

Meine Frage ist, warum strongSelf ist nicht Null nach sample = nil. Ist es, weil es innerhalb des Verschlusses vor sample = nil

+1

Wenn Sie 'sample = nil' setzen, wird nur der eine starke Verweis auf die' Sample' aufgelöst. Aber es hat keine Auswirkung auf andere starke Referenzen, die da draußen sein könnten (wie zum Beispiel "strongSelf", das zugewiesen wurde, bevor du "sample = nil" benutzt hast). Der ganze Zweck, ein "strongSelf" -Muster innerhalb der '[weak self]' -Schließung (manchmal scherzhaft "strongSelf/weakSelf-Tanz" genannt) zu machen, besteht darin, sicherzustellen, dass, wenn diese 'Probe' nicht freigegeben wurde, als diese Schließung begann, es wird es bis zum Abschluss dieser Schließung herum behalten. – Rob

+0

@Rob: Ich glaube ich habe das aber nicht 100% verstanden. Vom OP aus, wenn die Schließung beginnt, wurde Sample noch nicht freigegeben, bis das erste 'additionOf (3, b: 3)' ausgeführt wird. Ich verstehe immer noch nicht, warum 'strongSelf' nicht verändert wird, weil das selbe nichts ist. – tonytran

+1

Es ist nicht, dass es von der Schließung "gefangen" wird. Einfach, dass der Verschluss eine neue, zweite starke Referenz zum Objekt "Sample" etabliert hat. Also, wenn Sie 'var sample: Sample? = Sample() ', es gab eine starke Referenz. Wenn der Code auf "guard leave strongSelf = self else ..." trifft, ergibt sich eine zweite starke Referenz für insgesamt zwei starke Referenzen. Wenn Sie im Hauptthread "sample = nil" ausgeführt haben, ist immer noch eine starke Referenz vorhanden. Nur wenn "strongSelf" außerhalb des Gültigkeitsbereichs liegt, wird diese endgültige starke Referenz aufgelöst und das Objekt wird freigegeben. – Rob

Antwort

3

Betrachten wir Ihr zweites Beispiel erfasst wird:

dispatch_async(dispatch_get_global_queue(0, 0)) { [weak self] in 
    guard let strongSelf = self else { return } 
    strongSelf.additionOf(3, b: 3) 
    usleep(500) 
    strongSelf.additionOf(3, b: 5) 
} 

Dies ist ein gemeinsames Muster, und es sagt effektiv „, wenn self hat freigegeben worden ist, return, da sonst ein etablieren starke Referenz, strongSelf, und pflegen Sie diese starke Referenz, bis die Schließung abgeschlossen ist. "

Also, in Ihrem Beispiel self war nicht nil, wenn dieser ausgelöst Block gestartet, so sobald wir strongSelf darauf verweisen zugewiesen, haben wir nun zwei starke Hinweise auf dieses Sample Objekt, sowohl die ursprüngliche sample Referenz und diesen neue strongSelf Referenz in diesem Verschluss.

Also, wenn Ihr anderer Thread seine eigene starke Referenz entfernt, sample, zu diesem Sample Objekt (entweder durch den Gültigkeitsbereich fallen oder durch explizite sample-nil Einstellung), diese strongSelf starke Referenz noch vorhanden ist und das Objekt hält von der Zuteilung (oder zumindest nicht, bis dieser abgetrennte Block beendet ist).

In Ihrem Kommentar oben, fragen Sie:

Ich verstehe immer noch nicht, warum strongSelf nicht, da selbst nil ist aus ...

Starke Referenzen nie nur auf nil gesetzt bekommen umziehen weil eine andere starke Referenz (auch wenn es die ursprüngliche starke Referenz war) auf nil gesetzt wurde. Dieses Verhalten einer Referenz, die auf nil gesetzt wird, gilt nur für weak Referenzen, nicht für starke Referenzen.

Wenn Ihr Code im ersten Thread sample = nil ausführt, wird nur eine starke Referenz entfernt. Es löscht das Objekt oder etwas ähnliches nicht. Es entfernt nur seine starke Referenz.Und jetzt, da der abgetrennte Block seine eigene starke Referenz hat, passiert nach sample = nil nur, dass das Objekt, das zwei starke Referenzen hatte, nur noch eine starke Referenz hat (die strongSelf Referenz im abgetrennten Block). Nur wenn diese letzte starke Referenz entfernt wird, wird das Objekt freigegeben und deinit wird aufgerufen.

+0

jetzt macht es total Sinn für mich zu wissen – tonytran