ARC - Die Bedeutung von __unsafe_unretained?

79

Ich möchte nur sicherstellen, dass ich es richtig gemacht habe:

  1. Muss ich __unsafe_unretainObjekte haben, die ich nicht besitze?
  2. Wenn ein Objekt ist __unsafe_unretainedMuss ich es assignin der verwenden @property? Bedeutet das, dass das Objekt nicht beibehalten wird und sich nur auf das Objekt bezieht, dem ich zugewiesen habe?
  3. Wann möchte ich es außer für Delegierte verwenden?
  4. Ist das eine ARC-Sache oder wurde sie schon früher benutzt?
Shannoga
quelle

Antworten:

192

Der LLVM Compiler 3.0 stellt vier neue Eigentümer - Qualifikation: __strong, __autoreleasing, __unsafe_unretained, und __weak. Die ersten drei sind gemäß Spezifikation auch außerhalb von ARC erhältlich .

Wie Joshua angibt, sind standardmäßig alle Zeiger __strongunter ARC. Dies bedeutet, dass ein Objekt, das diesem Zeiger zugewiesen ist, so lange beibehalten wird, wie dieser Zeiger darauf verweist. Dies ist für die meisten Dinge in Ordnung, eröffnet jedoch die Möglichkeit, Zyklen beizubehalten, wie ich in meiner Antwort hier beschreibe . Wenn Sie beispielsweise ein Objekt haben, das ein anderes Objekt als Instanzvariable enthält, dieses zweite Objekt jedoch eine starke Verknüpfung zum ersten Objekt als Delegat aufweist, werden die beiden Objekte niemals freigegeben.

Aus diesem Grund existieren die __unsafe_unretainedund __weakQualifikanten. Sie werden am häufigsten für Delegaten verwendet, bei denen Sie eine Eigenschaft für diesen Delegaten mit dem Attribut weakoder definieren unsafe_unretained( assigneffektiv unsafe_unretained) und diese dann durch Markieren der jeweiligen Instanzvariablen mit __weakoder abgleichen __unsafe_unretained. Dies bedeutet, dass die Delegateninstanzvariable weiterhin auf das erste Objekt verweist, dieses Objekt jedoch nicht beibehalten wird, wodurch der Aufbewahrungszyklus unterbrochen wird und beide Objekte freigegeben werden können.

Abgesehen von Delegierten ist dies nützlich, um andere Aufbewahrungszyklen zu unterbrechen, die sich möglicherweise in Ihrem Code bilden. Das Leaks-Instrument enthält jetzt eine Zyklenansicht, in der die in Ihrer Anwendung erkannten Aufbewahrungszyklen grafisch angezeigt werden.

Beides __unsafe_unretainedund __weakverhindern das Zurückhalten von Objekten, jedoch auf leicht unterschiedliche Weise. Denn __weakder Zeiger auf ein Objekt wird nilbei der Freigabe des Objekts , auf das er zeigt, konvertiert , was ein sehr sicheres Verhalten ist. Wie der Name schon sagt, __unsafe_unretainedwird weiterhin auf den Speicher verwiesen, in dem sich ein Objekt befand, auch nachdem es freigegeben wurde. Dies kann zu Abstürzen führen, wenn auf das freigegebene Objekt zugegriffen wird.

Warum würden Sie dann jemals verwenden __unsafe_unretained? Leider __weakwird nur für iOS 5.0 und Lion als Bereitstellungsziele unterstützt. Wenn Sie auf iOS 4.0 und Snow Leopard zurückgreifen möchten, müssen Sie das __unsafe_unretainedQualifikationsmerkmal oder etwas wie Mike Ashs MAZeroingWeakRef verwenden .

Brad Larson
quelle
2
Und natürlich __unsafe_unretainedkann es nützlich sein, C-Arrays von NSStringKonstanten und dergleichen zu definieren, z. B.NSString __unsafe_unretained *myStrings = { @"Foo", @"Bar", @"Baz", nil };
jlehr
2
@shannoga - Nein, Sie müssen manuell __weakals Qualifikationsmerkmal angeben , damit diese Art von Zeigern verwendet werden kann. Sie können immer noch __unsafe_unretainedmit einem reinen 5.0-Ziel verwenden und es verhält sich nicht so __weak. Wenn Sie etwas möchten, das zwischen den beiden Modi wechselt, je nachdem, ob Ihr Ziel dies unterstützt, können Sie eine compilerspezifische Definition verwenden, wie ich sie hier vorschlage: stackoverflow.com/a/8594878/19679
Brad Larson
4
@jlehr - NSString *myStrings = { @"Foo", @"Bar" };ist keine gültige Objective-C-Syntax; @"Foo"hat Typ NSString*für sich. Vielleicht hast du es gemeint NSString *myStrings[] = { @"Foo", @"Bar" };, aber in diesem Fall verstehe ich nicht wirklich, wie __unsafe_unretainedes besonders nützlich wäre.
Quuxplusone
2
@Quuxplusone In beiden Punkten richtig - ich habe C-Arrays mit Strukturen verwechselt. Was ich hätte sagen sollen, ist, dass __unsafe_unretainedC-Struktur-Mitglieder nützlich sein können, die auf NSString-Konstanten verweisen, z. B.struct foo { __unsafe_unretained NSString * const s; int x; };
jlehr
1
Hat auch Auswirkungen auf Class. Siehe: stackoverflow.com/a/14245894/392847
Quintin Willison
4
  1. Nein, Sie können auch weakObjekte verwenden, die Sie nicht besitzen.
  2. Nein, Sie können auch unsafe_unretainedauf dem Grundstück verwenden.
  3. Mein Verständnis ist, dass unsafe_unretainedGegenstände genau so sind weak, ohne die zusätzliche Sicherheit, sie zu löschen, wenn der Gegenstand, auf den sie zeigen, freigegeben wird (und der damit verbundene Overhead).
  4. Dies ist eine reine ARC-Sache.
Sergey Kalinichenko
quelle
Eigentlich seltsam genug, unsafe_unretainedIvars, wenn zur Laufzeit gesetzt, verhalten sich genauso wie strongdiejenigen, die führt mich zu glauben , dass unsafe_unretainedist einfach ein Compiler Hinweis, während schwach ist , nicht. Weitere Informationen hier: stackoverflow.com/questions/11621028/…
Richard J. Ross III
4

__unsafe_unretainedist identisch mit dem Standardspeicher eines Objekts vor ARC. Bei ARC bedeutet die Standardeinstellung jetzt, __strongdass Sie eine Referenz darauf haben, bis Ihre Referenz den Gültigkeitsbereich verlässt.

Joshua Weinberg
quelle
1

Eine weitere Beobachtung zu __unsafe_unretained: Ich habe Abstürze in meiner App auf dem Gerät und NICHT im Simulator mit iVars, die als __unsafe_unretained deklariert sind! Ja, es war ein Fehler im Code der ARC-Migration, aber es war das erste Mal, dass ich einen solchen Unterschied zwischen Gerät und Simulator bemerkte.

Gerd
quelle