Was bedeutet es in Objective-C, einem Starken innerhalb eines Blocks ein schwaches zuzuweisen?

Was bedeutet es in Objective-C, einem strong in einem Block einen weak zuzuweisen? Was passiert hinter der Szene?

z.B.

__weak __typeof(self) wself = self;

void (^cmd)() = ^(){
    __strong __typeof(self) sself = wself;
    if (!sself) return;
    ...
};
0
@Rob, danke, bearbeitet.
hinzugefügt der Autor Boon, Quelle
Ich hatte einen wirklich komplexen Netzwerkcode, der sowohl das starke als auch das schwache Selbst verwendete, und ich schrieb einen Blog darüber, der es vielleicht klarer machen könnte: dhoerl.wordpress.com/2013/04/23/…
hinzugefügt der Autor David H, Quelle
Ich bin mir da nicht sicher, aber ich denke, das Zuweisen von schwach zu stark ist eine Logik, um einen Verweis auf das Objekt hinzuzufügen, weil schwach das referenzierte Objekt nicht am Leben erhält und wenn es Wiederholungen gibt, macht es eine neue Referenz ...
hinzugefügt der Autor Saad Chaudhry, Quelle
@DavidH guten einen Boon auch einen Blick auf stackoverflow.com/questions/11013587/…
hinzugefügt der Autor Saad Chaudhry, Quelle

2 Antworten

Die Absicht hier ist zweifach:

  1. First, is the use of:

    __weak __typeof(self) wself = self;
    

    This ensures that the cmd block does not maintain a strong reference to self. This ensures that, if cmd was an instance variable of the class, that you don't end up with a strong reference cycle. If you don't use this wself pattern, the class that has cmd as an instance variable would never be released and you'd leak the object that has cmd as an instance variable.

    For more information, see the Avoid Strong Reference Cycles when Capturing self section of the Programming with Objective-C: Working With Blocks document.

  2. Second, the use of the following within the block:

    __strong __typeof(self) sself = wself;
    if (!sself) return;
    

    This ensures that, if the block starts execution, if wself was already deallocated, the block would quit. But if wself has not yet been deallocated, by assigning sself, you're making sure that the object will be retained during the execution of the block.

    Also, if you reference any ivars in the block, be aware that you want to dereference them (because otherwise there is an implicit reference to self in the block, potentially leading to that strong reference cycle). But you cannot dereference ivars using a weak pointer (e.g. wself->someIvar is not permitted), but you can with this local strong pointer (e.g. sself->someIvar is ok). Generally you shouldn't be dereferencing ivars anyway, but rather use properties, but nonetheless it's another reason to use a local strong reference to self.

Oft sehen Sie dieses Konstrukt in Verbindung mit einer Klasseneigenschaft (oder einem ivar):

@property (nonatomic, copy) void (^commandBlock)(void);

Und aus Gründen der Konvention sehen Sie im Allgemeinen mehr beschreibende Variablennamen, weakSelf und strongSelf , also:

__weak __typeof(self) weakSelf = self;

self.commandBlock = ^(){
    __strong __typeof(self) strongSelf = weakSelf;
    if (!strongSelf) return;
    ...
};

Dieses weakSelf / strongSelf -Muster ist sehr häufig, wenn Sie eigene Blockeigenschaften für Ihre Klasse haben und (a) starke Referenzzyklen verhindern wollen (auch Retain-Zyklen genannt); aber (b) möchte sicherstellen, dass das fragliche Objekt nicht mitten in der Ausführung des Blocks freigegeben werden kann.

0
hinzugefügt
Wie das Chunking von Wissen. Vielen Dank.
hinzugefügt der Autor Boon, Quelle
Sehr gute Antwort.
hinzugefügt der Autor Lorenzo B, Quelle
@newacct Du verstehst mich falsch. Aber vielleicht ist es egal: Wenn Ihr Standpunkt ist, dass die Race-Bedingung unwahrscheinlich ist, ist das wahr (aber alle Race-Bedingungen sind inhärent unwahrscheinlich). Wenn Ihr Punkt ist, dass es nie passiert, dann stimmen wir zu widersprechen. Aber siehe Apples Diskussion über "nicht-triviale Zyklen" am Ende der ARC führt neue Lifetime Qualifiers ein Ab
hinzugefügt der Autor Rob, Quelle
"Indem Sie sich selbst zuweisen, stellen Sie sicher, dass das Objekt während der Ausführung des Blocks beibehalten wird." Ich habe Mühe zu sehen, wie Deallokation realistisch passieren kann. Der Block wird entweder über das self -Objekt aufgerufen oder nicht. 1) Wenn es nicht durch self aufgerufen wird, muss etwas anderes eine (starke) Referenz auf den Block (oder etwas, das den Block behält) haben. Daher wird der Block (oder etwas, dem er gehört) zuerst als Instanzvariable in self gespeichert und dann an etwas zurückgegeben, das vor dem self
hinzugefügt der Autor newacct, Quelle
2) Wenn es über das self -Objekt aufgerufen wird (durch einen Zeiger auf das self -Objekt), ist dies analog zum Aufruf einer Methode auf dem self Objekt. Dies liegt daran, dass self in Methoden in ARC nicht beibehalten wird. Also kann jede Situation, die in der Mitte des Blocks, der durch das Objekt irgendwie aufgerufen wird, eine Deallokation verursachen, in analoger Weise auch in der Mitte einer durch das Objekt aufgerufenen Methode auf die gleiche Weise geschehen. Anscheinend entschieden die ARC-Jungs, dass dies so ungewöhnlich war
hinzugefügt der Autor newacct, Quelle
@Rob: Ich habe nicht davon ausgegangen, wie der Block ausgeführt wird. Ich sage, dass wenn der Netzwerkvorgang im Hintergrund ausgeführt wird und von diesem Hintergrundprozess beibehalten wird, er normalerweise nicht vom Ansichtscontroller beibehalten werden muss. Außerdem sollte alles, was die Benutzeroberfläche aktualisiert, auf dem Hauptthread ausgeführt werden, sodass dieses Problem nicht auftreten sollte.
hinzugefügt der Autor newacct, Quelle

Wenn Sie keine schwache -Referenz auf strong zuweisen, kann das Objekt, auf das durch die weak -Referenz verwiesen wird, mitten in der Blockausführung freigegeben werden. etwas, was du vielleicht nicht erwartest. Wenn Sie strong zuweisen, wird das Objekt so lange beibehalten, wie sich die starke Referenz im Bereich befindet (es sei denn, das Objekt wurde bereits vor der Zuweisung freigegeben).

Wenn Sie einem starken Compiler einen schwachen Verweis zuweisen, wird Objective-C-Laufzeitfunktionsaufruf in den Code eingefügt, der den Objektreferenzzähler bei Bedarf erhöht, um ihn beizubehalten. Wenn die starke Variable den Gültigkeitsbereich verlässt (oder früher, nach der letzten Verwendung der starken Variablen), dekrementiert ein anderer vom Compiler eingefügter Aufruf den Referenzzähler.

0
hinzugefügt
Was passiert hinter der Szene? Führt die Zuweisung zu stark dazu, dass die Ref-Zählung ansteigt?
hinzugefügt der Autor Boon, Quelle
@Boon Während wir nicht mehr in "Retain counts" denken sollen, ja, die Zuweisung zu lokalen starken Variablen innerhalb des Blocks wird dazu führen, dass der Retain-Zähler erhöht wird, wenn der Block ausgeführt wird (aber nicht vorher) und die Retain-Anzahl wird reduziert, wenn der Block die Ausführung beendet und die self -Variable den Gültigkeitsbereich verlässt.
hinzugefügt der Autor Rob, Quelle
Ich kenne nicht alle Details der ARC-Maschinerie (es kann einige Optimierungen durchführen), aber konzeptionell können Sie denken, dass der Referenzzähler inkrementiert wird, wenn Sie den Verweis auf eine starke Variable zuweisen.
hinzugefügt der Autor yurish, Quelle