NSNotificationCenter und sicheres Multithreading

8

Da Objekte auch während eines Methodenaufrufs freigegeben werden können ( link ) *, ist es für ein Objekt sicher, sich für einen Thread zu registrieren und Benachrichtigungen zu erhalten, die zu diesem Thread gehören unterscheidet sich von dem, von dem erwartet wird, dass es freigegeben wird?

Als Referenz finden Sie in der Dokumentation , dass

  

In einer Multithread-Anwendung werden Benachrichtigungen immer in dem Thread bereitgestellt, in dem die Benachrichtigung gepostet wurde. Dies ist möglicherweise nicht der Thread, in dem sich ein Beobachter registriert hat.

Wichtig ist auch die Tatsache, dass NSNotificationCenter keinen starken Bezug zu Objekten hat, die für den Empfang von Benachrichtigungen registriert sind.

Hier ist ein Beispiel, das die Situation konkreter machen könnte:

%Vor%

Ein Objekt mit dieser Implementierung empfängt SomeNotification auf Thread X. Before -handleNotification: returns, die letzte starke Referenz auf das Objekt (im Code, den ich sehen kann) ist unterbrochen.

  1. Habe ich Recht, wenn ich das denke:

    a. Wenn NSNotificationCenter eine starke Referenz auf das Objekt vor dem Aufruf von -handleNotification verwendet, wird das Objekt erst nach der Verwendung von -handleNotification: returns und

    freigegeben

    b. Wenn NSNotificationCenter vor dem Aufrufen von -handleNotification keine starke Referenz auf das Objekt verwendet, kann das Objekt vor der Verwendung von -handleNotification: zurückgeben

  2. Welcher Weg (a oder b) funktioniert? Ich habe dieses Thema in der Dokumentation noch nicht gefunden, aber es scheint etwas wichtig zu sein, NSNotificationCenter sicher in einer Multithread-Umgebung zu verwenden.

UPDATE: Die Antwort im oben genannten Link wurde aktualisiert und zeigt an, dass "ARC einen Aufruf auf einer schwachen Referenz beibehält und freigibt". Dies bedeutet, dass ein Objekt während eines Methodenaufrufs nicht freigegeben werden sollte.

    
Andrew Hershberger 06.12.2012, 13:48
quelle

2 Antworten

8
___ tag123objectivec ___ Dieses Tag sollte nur bei Fragen verwendet werden, die sich auf Objective-C-Funktionen beziehen oder von Code in der Sprache abhängen. Die Tags [Kakao] und [Kakao-Touch] sollten verwendet werden, um nach Frameworks oder Klassen von Apple zu fragen. Verwenden Sie die zugehörigen Tags [ios], [macos], [apple-watch] und [tvos] für Probleme, die für diese Plattformen spezifisch sind. ___ tag123multithreading ___ Multi-Threading ist die Fähigkeit eines Computers oder eines Programms, Arbeit gleichzeitig oder asynchron auszuführen, indem mehrere gleichzeitige Ausführungsströme (im Allgemeinen als Threads bezeichnet) verwendet werden. ___ tag123nsnotificationcenter ___ NSNotificationCenter ermöglicht das Senden und Registrieren von Benachrichtigungen im Foundation-Framework, das von Apple bereitgestellt wird. ___ qstntxt ___

Da Objekte auch während eines Methodenaufrufs freigegeben werden können ( link ) *, ist es für ein Objekt sicher, sich für einen Thread zu registrieren und Benachrichtigungen zu erhalten, die zu diesem Thread gehören unterscheidet sich von dem, von dem erwartet wird, dass es freigegeben wird?

Als Referenz finden Sie in der Dokumentation , dass

  

In einer Multithread-Anwendung werden Benachrichtigungen immer in dem Thread bereitgestellt, in dem die Benachrichtigung gepostet wurde. Dies ist möglicherweise nicht der Thread, in dem sich ein Beobachter registriert hat.

Wichtig ist auch die Tatsache, dass NSNotificationCenter keinen starken Bezug zu Objekten hat, die für den Empfang von Benachrichtigungen registriert sind.

Hier ist ein Beispiel, das die Situation konkreter machen könnte:

%Vor%

Ein Objekt mit dieser Implementierung empfängt SomeNotification auf Thread X. Before -handleNotification: returns, die letzte starke Referenz auf das Objekt (im Code, den ich sehen kann) ist unterbrochen.

  1. Habe ich Recht, wenn ich das denke:

    a. Wenn NSNotificationCenter eine starke Referenz auf das Objekt vor dem Aufruf von -handleNotification verwendet, wird das Objekt erst nach der Verwendung von -handleNotification: returns und

    freigegeben

    b. Wenn NSNotificationCenter vor dem Aufrufen von -handleNotification keine starke Referenz auf das Objekt verwendet, kann das Objekt vor der Verwendung von -handleNotification: zurückgeben

  2. Welcher Weg (a oder b) funktioniert? Ich habe dieses Thema in der Dokumentation noch nicht gefunden, aber es scheint etwas wichtig zu sein, NSNotificationCenter sicher in einer Multithread-Umgebung zu verwenden.

UPDATE: Die Antwort im oben genannten Link wurde aktualisiert und zeigt an, dass "ARC einen Aufruf auf einer schwachen Referenz beibehält und freigibt". Dies bedeutet, dass ein Objekt während eines Methodenaufrufs nicht freigegeben werden sollte.

    
___ answer39222902 ___

NSNotificationCenter verwendet keine starke Referenz auf das Objekt, daher muss der Beobachter vor der Freigabe entfernt werden. Wenn ARC aktiviert ist und die handleNotification aufgerufen wird, wird der Beobachter nicht freigegeben, da das Aufrufen von handleNotification die Retain-Anzahl erhöht. Wenn der Beobachter vor der Veröffentlichung der Benachrichtigung freigegeben wird, entfernt NSNotificationCenter ihn aus den Beobachtern, während Sie in der dealloc-Methode schreiben, so dass handleNotification nicht aufgerufen wird. NSNotificationCenter ruft Benachrichtigungshandler synchron auf, während eine Benachrichtigung gesendet wird.

    
___ qstnhdr ___ NSNotificationCenter und sicheres Multithreading ___ antwort13746409 ___

Ich empfehle immer, wenn Sie sehen, dass Benachrichtigungen in anderen Threads als main herumfliegen, und Sie sehen, dass Löschungen im Hintergrund stattfinden, ist Ihr Threading möglicherweise zu kompliziert. ObjC ist keine Thread-fröhliche Sprache. Die meiste Threading-Arbeit sollte in Form von kurzlebigen Blöcken in Warteschlangen erfolgen. Sie können Benachrichtigungen einfach zurück zum Hauptthread posten, sollten aber häufig keine Benachrichtigungen konsumieren.

Das heißt, der beste Weg heute, Multi-Thread-Benachrichtigungen zu verwalten, ist addObserverForName:object:queue:usingBlock: . Dies ermöglicht Ihnen eine viel größere Kontrolle über die Lebensdauer. Das Muster sollte etwa so aussehen:

%Vor%

Beachte den Gebrauch von weakself / strongself. Wir vermeiden eine Retain-Schleife mit schwachem Selbst. Wenn wir zurückkommen, nehmen wir zuerst eine starke Referenz. Wenn wir noch existieren, sind wir für den Rest des Blocks gesperrt (daher können wir in handleNotification: nicht aufheben). Wenn wir nicht existieren, wird die Benachrichtigung verworfen. (Beachten Sie, dass schwache Referenzen vor dem Aufruf von dealloc effektiv auf Null gesetzt werden. Siehe objc_loadWeak .) I ' m mit mainQueue hier, aber Sie könnten sicherlich eine andere Warteschlange verwenden.

In den "alten Tagen" (vor 10.6) habe ich dieses Problem durch Kontrolle der Lebensdauer von Objekten entworfen. Im Grunde habe ich so entworfen, dass kurzlebige Objekte nicht auf Benachrichtigungen von anderen Threads hören. Das war viel einfacher, als es sich anhört, denn in Pre-10.6-Code kann Threading ziemlich selten gehalten werden (und IMO sollte immer noch auf einem niedrigen Level gehalten werden). NSNotificationCenter wurde für diese Low-Thread-Welt entwickelt.

Beachten Sie auch, dass -[NSNotificationCenter addObserver:selector:name:object:] im Gegensatz zu -[NSNotificationCenter addObserverForName:object:queue:usingBlock:] ein undurchsichtiges Objekt zurückgibt, das als Beobachter fungiert. Sie müssen dieses Objekt verfolgen, damit Sie den Beobachter später entfernen können.

    
___
Rob Napier 06.12.2012, 15:03
quelle
0

NSNotificationCenter verwendet keine starke Referenz auf das Objekt, daher muss der Beobachter vor der Freigabe entfernt werden. Wenn ARC aktiviert ist und die handleNotification aufgerufen wird, wird der Beobachter nicht freigegeben, da das Aufrufen von handleNotification die Retain-Anzahl erhöht. Wenn der Beobachter vor der Veröffentlichung der Benachrichtigung freigegeben wird, entfernt NSNotificationCenter ihn aus den Beobachtern, während Sie in der dealloc-Methode schreiben, so dass handleNotification nicht aufgerufen wird. NSNotificationCenter ruft Benachrichtigungshandler synchron auf, während eine Benachrichtigung gesendet wird.

    
James 30.08.2016 08:54
quelle