Objective-C ARC: stark gegen behalten und schwach gegen zuweisen


367

Es gibt zwei neue Speicherverwaltungsattribute für Eigenschaften, die von ARC eingeführt wurden, strongund weak.

Abgesehen davon copy, was offensichtlich etwas völlig anderes ist, gibt es Unterschiede zwischen strongvs retainund weakvs assign?

Nach meinem Verständnis besteht der einzige Unterschied darin, dass der Zeiger weakzugewiesen wird nil, während dies assignnicht der Fall ist. Dies bedeutet, dass das Programm abstürzt, wenn ich eine Nachricht an den Zeiger sende, sobald dieser freigegeben wurde. Aber wenn ich benutze weak, wird dies niemals passieren, da das Senden von Nachrichten an nilnichts bewirkt.

Ich kenne keine Unterschiede zwischen strongund retain.

Gibt es einen Grund, warum ich assignund retainin neuen Projekten verwenden sollte, oder wird die Art von veraltet?


12
Es gibt drei neue Speicherverwaltungsattribute für Eigenschaften, die von ARC eingeführt wurden strong, weakund unsafe_unretained.
NJones

5
@NJones Es gibt zwei Eigenschaftsattribute ( weakund strong) und 4 variable Lebensdauer Qualifizierer ( __strong, __weak, __unsafe_unretained, __autoreleasing). Siehe die ARC-Hinweise unten.
Snowcrash

1
@SnowCrash Es gab eine Version von Xcode, wahrscheinlich eine Entwicklervorschau, bei der die Verwendung assignbeim Kompilieren mit ARC ein Fehler war. Es gibt viele gelöschte Antworten dazu. Es scheint, dass dies vor der endgültigen Veröffentlichung geändert wurde. unsafe_unretainedist das bevorzugte Attribut für viele von uns Early Adopters. unsafe_unretainedEinen Beweis dafür, dass es sich um ein gültiges Attribut handelt, finden Sie in Apples "Programmieren mit Objective-C" im Abschnitt "Kapselung von Daten" unter der Überschrift "Verwenden Sie unsichere nicht zurückgehaltene Referenzen für einige Klassen". Was besagt: "Für eine Eigenschaft bedeutet dies die Verwendung des Attributs unsafe_unretained:"
NJones

Antworten:


230

Aus den Versionshinweisen zum Übergang zu ARC (das Beispiel im Abschnitt über Eigenschaftsattribute).

// The following declaration is a synonym for: @property(retain) MyClass *myObject;

@property(strong) MyClass *myObject;

So strongist es auch retainin einer Eigenschaftsdeklaration.

Für ARC-Projekte, die ich stronganstelle von verwenden würde retain, würde ich assignfür C-Grundelementeigenschaften und weakfür schwache Verweise auf Objective-C-Objekte verwenden.


11
Tatsächlich ist es unter ARC ein Kompilierungsfehler, der assignfür ein Objekt verwendet werden muss. Sie müssen entweder weakoder unsafe_unretained(was natürlich unsicher ist) verwenden, wenn Sie die Eigenschaft nicht behalten möchten.
Cobbal

5
assignKompiliert für mich in ARC-Projekten mit Deployment Target 4.0.
Pascal

8
@Pascal: Schwache Referenzen sind in Bereitstellungszielen nicht zulässig, bei denen das Betriebssystem nicht 5.0 oder höher ist. Für ältere Projekte können Sie also weiterhin Zuweisen verwenden, aber wenn Sie zu neueren Versionen wechseln, müssen Sie zu schwach wechseln
Mattia

1
Sieht wie Xcode 4 (mit ARC) erzeugt NSManagedObject Subklassen Verwendung retainvs. strong. Ich nehme an, das ist größtenteils harmlos, aber ich stelle mir vor, es sollte strongaus Gründen der Konsistenz sein ... oder vielleicht spielt es keine Rolle. stackoverflow.com/questions/7796476/…
Joe D'Andrea

3
@JeremyP Ja, Ihre Antwort ist genau richtig. Ich habe auf @Mattia reagiert. Ich habe darauf hingewiesen, dass dies assignin einigen Fällen noch gültig ist.
Steven Oxley

606

Nachdem ich so viele Artikel über Stackoverflow-Beiträge und Demoanwendungen gelesen hatte, um die Attribute variabler Eigenschaften zu überprüfen, entschied ich mich, alle Attributinformationen zusammenzufassen:

  1. atomar // Standard
  2. nichtatomar
  3. strong = beibehalten // Standard
  4. schwach
  5. behalten
  6. // Standard zuweisen
  7. unsafe_unretained
  8. Kopieren
  9. schreibgeschützt
  10. readwrite // default

Unten finden Sie den detaillierten Artikel-Link, über den Sie alle oben genannten Attribute finden, die Ihnen definitiv helfen werden. Vielen Dank an alle, die hier die besten Antworten geben !!

Variable Eigenschaftsattribute oder Modifikatoren in iOS

1.strong (iOS4 = behalten)

  • es heißt "behalte das auf dem Haufen, bis ich nicht mehr darauf zeige"
  • mit anderen Worten "Ich bin der Besitzer, Sie können dies nicht freigeben, bevor Sie mit dem gleichen Ziel wie" Beibehalten "zielen."
  • Sie verwenden strong nur, wenn Sie das Objekt beibehalten müssen.
  • Standardmäßig sind alle Instanzvariablen und lokalen Variablen starke Zeiger.
  • Wir verwenden im Allgemeinen stark für UIViewController (Eltern des UI-Elements).
  • strong wird mit ARC verwendet und hilft Ihnen im Grunde, indem Sie sich keine Gedanken über die Anzahl der Objekte machen müssen. ARC gibt es automatisch für Sie frei, wenn Sie damit fertig sind. Wenn Sie das Schlüsselwort strong verwenden, bedeutet dies, dass Sie das Objekt besitzen.

Beispiel:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;

2.schwach -

  • es heißt "behalte das so lange, wie jemand anderes stark darauf hinweist"
  • das gleiche wie zuweisen, nicht behalten oder freigeben
  • Eine "schwache" Referenz ist eine Referenz, die Sie nicht behalten.
  • Wir verwenden im Allgemeinen schwach für IBOutlets (UIViewController's Childs). Dies funktioniert, weil das untergeordnete Objekt nur so lange existieren muss, wie das übergeordnete Objekt.
  • Eine schwache Referenz ist eine Referenz, die das referenzierte Objekt nicht vor der Erfassung durch einen Garbage Collector schützt.
  • Schwach ist im Wesentlichen zuzuweisen, eine nicht zurückgehaltene Eigenschaft. Außer wenn das Objekt freigegeben wird, wird der schwache Zeiger automatisch auf Null gesetzt

Beispiel:

@property (weak, nonatomic) IBOutlet UIButton *myButton;

@synthesize myButton;

Starke und schwache Erklärung, danke an BJ Homer :

Stellen Sie sich vor, unser Objekt ist ein Hund und der Hund möchte weglaufen (freigegeben werden).

Starke Zeiger sind wie eine Leine am Hund. Solange Sie die Leine am Hund befestigt haben, rennt der Hund nicht weg. Wenn fünf Personen ihre Leine an einem Hund befestigen (fünf starke Zeiger auf ein Objekt), rennt der Hund nicht weg, bis alle fünf Leinen gelöst sind.

Schwache Zeiger hingegen sind wie kleine Kinder, die auf den Hund zeigen und sagen: "Schau! Ein Hund!" Solange der Hund noch an der Leine ist, können die kleinen Kinder den Hund noch sehen und sie werden immer noch darauf zeigen. Sobald jedoch alle Leinen gelöst sind, rennt der Hund weg, egal wie viele kleine Kinder darauf zeigen.

Sobald der letzte starke Zeiger (Leine) nicht mehr auf ein Objekt zeigt, wird die Zuordnung des Objekts aufgehoben und alle schwachen Zeiger werden auf Null gesetzt.

Wann verwenden wir schwach?

Das einzige Mal, wenn Sie schwach verwenden möchten, ist, wenn Sie Aufbewahrungszyklen vermeiden möchten (z. B. behält der Elternteil das Kind und das Kind behält den Elternteil, sodass keiner jemals freigegeben wird).

3. behalten = stark

  • Es wird beibehalten, der alte Wert wird freigegeben und es wird beibehalten zugewiesen. Gibt an, dass der neue Wert gesendet werden soll
  • bei Zuordnung behalten und den alten Wert gesendet -freigabe
  • behalten ist das gleiche wie stark.
  • Apple sagt, wenn Sie schreiben, behalten Sie es automatisch konvertiert / funktioniert nur wie stark.
  • Methoden wie "Alloc" beinhalten ein implizites "Retain"

Beispiel:

@property (nonatomic, retain) NSString *name;

@synthesize name;

4.zuweisen

  • Zuweisen ist die Standardeinstellung und führt einfach eine Variablenzuweisung durch
  • assign ist ein Eigenschaftsattribut, das dem Compiler mitteilt, wie die Setter-Implementierung der Eigenschaft synthetisiert werden soll
  • Ich würde Assign für primitive C-Eigenschaften und schwach für schwache Verweise auf Objective-C-Objekte verwenden.

Beispiel:

@property (nonatomic, assign) NSString *address;

@synthesize address;

5
2. "Eine schwache Referenz ist eine Referenz, die das referenzierte Objekt nicht vor der Sammlung durch einen Garbage Collector schützt" - Ziel c enthält keinen Garbage Collector.
Bucherland

1
Diese Hierarchie wird von iOS automatisch verwaltet. Lesen Sie mehr über das MVC-Konzept. Ich meine, wenn ViewContorller präsentiert wird, lädt iOS seine Ansichtshierarchie auf dem Bildschirm (wodurch fehlende Ansichten erstellt werden). Wenn ein anderer ViewController angezeigt wird, wird diese erste Hierarchie von Ansichten freigegeben. Wenn Sie jedoch in ViewController "stark" sind, kann diese Ansicht nicht freigegeben werden, wenn sie sich außerhalb des Bildschirms befindet. Dies kann schwerwiegende Auswirkungen auf den Gerätespeicher und die Verlangsamung der App haben. (Natürlich haben Geräte viel Speicher und Sie würden auf jeden Fall in 5-10 Bildschirm App in Ordnung sein, aber in riesigen App werden Sie in Schwierigkeiten geraten)
Bucherland

1
Wann verwenden wir schwach? 1. Für UI-Objekte, 2. Delegierte, 3. Blöcke (schwaches Selbst sollte anstelle von Selbst verwendet werden, um Speicherzyklen zu vermeiden (wie oben erwähnt)
Bucherland

1
Diese großartige Antwort enthält einen Fehler: "ARC gibt sie automatisch für Sie frei, wenn Sie damit fertig sind". Dies ist nicht richtig. ARC gibt schwache Objekte automatisch frei, wenn keine Zeiger darauf vorhanden sind. Stark - ist ein Synonym für das Behalten, daher bleibt das Objekt erhalten und es liegt in unserer Verantwortung, das Objekt auf Null zu setzen
Ashwin G

1
@RDC, was bedeutet defaultdas? Wenn ich es benutze @property (nonatomic) NSString *stringist strong? Oder assign? Weil beide Standardeinstellungen sind.
Iulian Onofrei

40

nichtatomar / atomar

  • Nichtatomar ist viel schneller als Atom
  • Verwenden Sie immer nichtatomar, es sei denn, Sie haben eine ganz bestimmte Anforderung an atomar, was selten sein sollte (atomar garantiert keine Thread-Sicherheit - blockiert nur den Zugriff auf die Eigenschaft, wenn sie gleichzeitig von einem anderen Thread festgelegt wird).

stark / schwach / zuweisen

  • Verwenden Sie strong , um Objekte beizubehalten. Obwohl das Schlüsselwort keep synonym ist, verwenden Sie stattdessen strong
  • Verwenden Sie schwach, wenn Sie nur einen Zeiger auf das Objekt haben möchten, ohne ihn beizubehalten. Dies ist nützlich, um das Beibehalten von Zyklen (dh Delegaten) zu vermeiden. Der Zeiger wird automatisch gelöscht, wenn das Objekt freigegeben wird
  • verwenden assign für primatives - genau wie schwach , außer es nicht nil aus dem Objekt , wenn sie freigegeben (Standardeinstellung)

(Optional)

Kopieren

  • Verwenden Sie diese Option, um eine flache Kopie des Objekts zu erstellen
  • Es wird empfohlen, unveränderliche Eigenschaften immer auf Kopieren festzulegen. Da veränderbare Versionen an unveränderliche Eigenschaften übergeben werden können, stellt copy sicher, dass Sie immer mit einem unveränderlichen Objekt arbeiten
  • Wenn ein unveränderliches Objekt übergeben wird, wird es beibehalten. Wenn ein veränderliches Objekt übergeben wird, wird es kopiert

schreibgeschützt

  • Verwenden Sie diese Option, um die Einstellung der Eigenschaft zu deaktivieren (verhindert das Kompilieren von Code, wenn ein Verstoß vorliegt).
  • Sie können ändern, was vom Getter geliefert wird, indem Sie die Variable entweder direkt über ihre Instanzvariable oder innerhalb der Getter-Methode selbst ändern

@Sakthimuthiah ist richtig, Sie müssen Ihre Antwort korrigieren.
Adela Toderici

@Sakthimuthiah ist falsch (und jeder andere, der es sagt). Atomic macht es NICHT threadsicher, obwohl es aufgrund seines Verhaltens leicht verwechselt werden kann. Bitte lesen Sie: stackoverflow.com/questions/12347236/…
Chris J

39

Soweit ich weiß strongund retainSynonyme sind, tun sie genau das Gleiche.

Dann weakist das fast so assign, wird aber automatisch auf Null gesetzt, nachdem das Objekt, auf das es zeigt, freigegeben wurde.

Das heißt, Sie können sie einfach ersetzen.

Es gibt jedoch einen Sonderfall, auf den ich gestoßen bin assign, anstatt weak. Nehmen wir an, wir haben zwei Eigenschaften delegateAssignund delegateWeak. In beiden ist unser Delegierter gespeichert, der uns besitzt, indem er die einzige starke Referenz hat. Der Delegat gibt die Zuordnung auf, daher wird auch unsere -deallocMethode aufgerufen.

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething];
    [delegateAssign doSomething];
}

Der Delegat befindet sich bereits im Freigabeprozess, ist jedoch noch nicht vollständig freigegeben. Das Problem ist, dass weakVerweise auf ihn bereits ungültig sind! Die Eigenschaft delegateWeakenthält null, delegateAssignenthält jedoch ein gültiges Objekt (wobei alle Eigenschaften bereits freigegeben und ungültig sind, aber noch gültig sind).

// Our delegate is deallocating and there is no other strong ref.
- (void)dealloc {
    [delegateWeak doSomething]; // Does nothing, already nil.
    [delegateAssign doSomething]; // Successful call.
}

Es ist ein ganz besonderer Fall, aber es zeigt uns, wie diese weakVariablen funktionieren und wann sie aufgehoben werden.



20

In Clangs Dokument zur automatischen Zählung von Objective-C (ARC) werden die Eigentumsqualifikatoren und Modifikatoren klar erläutert:

Es gibt vier Eigentumsmerkmale:

  • __ Autoreleasing
  • __ stark
  • __ * unsafe_unretained *
  • __ __ schwach

Ein Typ ist nicht trivial eigentumsqualifiziert, wenn er mit __ autoreleasing , __ strong qualifiziert ist oder __ schwach qualifiziert ist .

Dann gibt es sechs Eigentumsmodifikatoren für deklariertes Eigentum:

  • assign impliziert __ * unsafe_unretained * Eigentum.
  • Kopie impliziert __ starkes Eigentum sowie das übliche Verhalten der Kopiersemantik auf dem Setter.
  • behalten impliziert __ starkes Eigentum.
  • stark impliziert __ starkes Eigentum.
  • * unsafe_unretained * impliziert __ * unsafe_unretained * Eigentum.
  • schwach bedeutet __ schwach Eigentum.

Mit Ausnahme von schwach sind diese Modifikatoren in Nicht-ARC-Modi verfügbar.

In Bezug auf die Semantik haben die Eigentumsqualifizierer in den fünf verwalteten Vorgängen unterschiedliche Bedeutung : Lesen, Zuweisen, Initialisieren, Zerstören und Verschieben, wobei wir uns meistens nur um den Unterschied im Zuweisungsvorgang kümmern.

Die Zuweisung erfolgt bei der Auswertung eines Zuweisungsoperators. Die Semantik variiert je nach Qualifikation:

  • Bei __ starken Objekten wird der neue Spitzenwert zuerst beibehalten. zweitens wird der l-Wert mit primitiver Semantik geladen; drittens wird der neue Pointee mit primitiver Semantik im l-Wert gespeichert; und schließlich wird der alte Pointee freigelassen. Dies wird nicht atomar durchgeführt; Eine externe Synchronisation muss verwendet werden, um dies bei gleichzeitigen Lasten und Speichern sicher zu machen.
  • Bei __ schwachen Objekten wird der l-Wert aktualisiert, um auf den neuen Pointee zu verweisen, es sei denn, der neue Pointee ist ein Objekt, das derzeit freigegeben wird. In diesem Fall wird der l-Wert auf einen Nullzeiger aktualisiert. Dies muss atomar in Bezug auf andere Zuweisungen an das Objekt, zum Lesen aus dem Objekt und zur endgültigen Freigabe des neuen Pointees ausgeführt werden.
  • Für __ * unsafe_unretained * -Objekte wird der neue Pointee unter Verwendung der primitiven Semantik im l-Wert gespeichert.
  • Bei __ Autoreleasing- Objekten wird der neue Pointee beibehalten, automatisch freigegeben und unter Verwendung der primitiven Semantik im l-Wert gespeichert.

Der andere Unterschied zwischen Lesen, Init, Zerstörung und Verschieben finden Sie in Abschnitt 4.2 Semantik im Dokument .


6

Angenommen, wir haben eine Methode mit dem Namen displayLocalVariable, um die Referenz zu Strong and Weak zu verstehen.

 -(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
  }

Im obigen Methodenbereich ist der Gültigkeitsbereich der Variablen myName auf die Methode displayLocalVariable beschränkt. Sobald die Methode abgeschlossen ist, wird die Variable myName, die die Zeichenfolge "ABC" enthält, aus dem Speicher freigegeben.

Was ist nun, wenn wir den Wert der Variablen myName während unseres gesamten Lebenszyklus des View Controllers beibehalten möchten? Zu diesem Zweck können wir die als Benutzername bezeichnete Eigenschaft erstellen, die einen starken Verweis auf die Variable myName (siehe self.username = myName;Code unten) enthält.

@interface LoginViewController ()

@property(nonatomic,strong) NSString* username;
@property(nonatomic,weak) NSString* dummyName;

- (void)displayLocalVariable;

@end

@implementation LoginViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

}

-(void)viewWillAppear:(BOOL)animated
{
     [self displayLocalVariable];
}

- (void)displayLocalVariable
{
   NSString myName = @"ABC";
   NSLog(@"My name is = %@", myName);
   self.username = myName;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end

Jetzt können Sie im obigen Code sehen, dass myName self.username zugewiesen wurde und self.username einen starken Verweis (wie wir in der Schnittstelle mit @property deklariert haben) auf myName hat (indirekt hat es einen starken Verweis auf die Zeichenfolge "ABC"). Daher wird der String myName erst dann aus dem Speicher freigegeben, wenn self.username aktiv ist.

  • Schwache Referenz

Erwägen Sie nun, myName dummyName zuzuweisen, was eine schwache Referenz ist. Self.dummyName = myName; Im Gegensatz zu starker Referenz hält Weak den myName nur so lange, bis eine starke Referenz auf myName vorhanden ist. Siehe folgenden Code, um die schwache Referenz zu verstehen.

-(void)displayLocalVariable
  {
     NSString myName = @"ABC";
     NSLog(@"My name is = %@", myName);
     self.dummyName = myName;
  }

Im obigen Code gibt es einen schwachen Verweis auf myName (dh self.dummyName hat einen schwachen Verweis auf myName), aber es gibt keinen starken Verweis auf myName, daher kann self.dummyName den myName-Wert nicht halten.

Betrachten Sie nun noch einmal den folgenden Code:

-(void)displayLocalVariable
      {
         NSString myName = @"ABC";
         NSLog(@"My name is = %@", myName);
         self.username = myName;
         self.dummyName = myName;
      } 

Im obigen Code hat self.username einen starken Verweis auf myName, daher hat self.dummyName jetzt auch nach dem Ende der Methode den Wert myName, da myName einen starken Verweis zugeordnet ist.

Wenn wir jetzt einen starken Verweis auf eine Variable machen, wird die Anzahl der Aufbewahrungen um eins erhöht und die Variable wird nicht freigegeben. Die Anzahl der Aufbewahrungen erreicht 0.

Hoffe das hilft.


2

Stark:

  • Die Eigenschaft wird nicht zerstört, aber erst wenn Sie die Eigenschaft auf Null setzen, wird das Objekt zerstört
  • Standardmäßig sind alle Instanzvariablen und lokalen Variablen starke Zeiger.
  • Sie verwenden strong nur, wenn Sie das Objekt beibehalten müssen.
  • Wir verwenden im Allgemeinen stark für UIViewController (Eltern des UI-Elements).
  • IOS 4 (nicht ARC) Wir können Retain KeyWord verwenden
  • IOS 5 (ARC) Wir können ein starkes Schlüsselwort verwenden

Beispiel: @property (stark, nichtatomar) ViewController * viewController;

@synthesize viewController;

Schwach

Standardmäßig automatisch abrufen und auf Null setzen

  • Wir verwenden im Allgemeinen schwach für IBOutlets (UIViewController's Childs) und delegieren
  • das gleiche wie zuweisen, nicht behalten oder freigeben

Beispiel: @property (schwach, nichtatomar) IBOutlet UIButton * myButton;

@synthesize myButton;


1

Die Unterschiede zwischen stark und behalten:

  • In iOS4 ist stark gleich zu behalten
  • Dies bedeutet, dass Sie das Objekt besitzen und es auf dem Heap behalten, bis Sie nicht mehr darauf zeigen
  • Wenn Sie behalten schreiben, funktioniert es automatisch genauso stark

Die Unterschiede zwischen schwach und zuordnen:

  • Eine „schwache“ Referenz ist eine Referenz, die Sie nicht behalten und die Sie behalten, solange jemand anderes stark darauf hinweist
  • Wenn das Objekt freigegeben wird, wird der schwache Zeiger automatisch auf Null gesetzt
  • Ein Eigenschaftsattribut "zuweisen" teilt dem Compiler mit, wie die Setter-Implementierung der Eigenschaft synthetisiert werden soll
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.