Wie ersetze ich schwache Referenzen, wenn ich ARC verwende und auf iOS 4.0 abziele?

87

Ich habe mit der Entwicklung meiner ersten iOS-App mit Xcode 4.2 begonnen und zielte auf iOS 5.0 mit einer Vorlage für "Dienstprogrammanwendungen" ab (die mit einem FlipsideViewController geliefert wird).

Ich habe gelesen, dass ARC eine Funktion zur Kompilierungszeit ist und daher auch mit iOS 4 kompatibel sein sollte. Deshalb habe ich versucht, meine App auf 4.3 auszurichten und sie zu kompilieren. Wenn ich das tue, erhalte ich folgende Fehlermeldung:

FlipsideViewController.m: Fehler: Automatische Referenzzählung Problem: Das aktuelle Bereitstellungsziel unterstützt keine automatisierten __schwachen Referenzen

Es verweist auf diese Zeile:

@synthesize delegate = _delegate;

Diese Variable wird deklariert als:

@property (weak, nonatomic) IBOutlet id <FlipsideViewControllerDelegate> delegate;

Ich verstehe, dass "schwache Referenzen" in iOS 4 nicht unterstützt werden, aber ich verstehe nicht wirklich, warum ich zunächst eine schwache Referenz verwenden möchte, und ich kann auch nicht herausfinden, wie ich Dinge umschreiben würde, um sie nicht zu verwenden ARC immer noch nutzen (schließlich soll es mit iOS 4 UND 5 funktionieren, oder?)

Mason G. Zhwiti
quelle

Antworten:

149

Um auf das ältere Betriebssystem abzuzielen, können Sie unsafe_unretainedanstelle von weakin Ihrer Eigenschaftsdeklaration verwenden, und es sollte meistens auf die gleiche Weise funktionieren. weakVerweise auf sich selbst, wenn ihr Ziel verschwindet, lassen jedoch unsafe_unretaineddie Möglichkeit offen, dass das Objekt, mit dem Sie verknüpfen, beim Freigeben in einen baumelnden Zeiger verwandelt wird. Letzteres entspricht dem Verhalten, das Sie assignbei der manuellen Speicherverwaltung als Eigenschaftsdeklaration verwendet haben .

Sie tun dies, um zu vermeiden, dass Zyklen beibehalten werden, die ich in meiner Antwort hier erwähne . Sie möchten keinen starken Zeiger auf etwas haben, das möglicherweise einen starken Zeiger zurück auf das ursprüngliche Objekt hat. Dann würde nichts richtig freigegeben werden.

Brad Larson
quelle
Danke für den Hinweis. Sie sagen "auf das ältere Betriebssystem abzielen ...". Bedeutet dies, dass ich unsafe_unretained nur in Builds der App verwenden sollte, die älter als 5.0 sind? Oder kann ich einfach unsafe_unretained in meinem Code verwenden und es so erstellen, dass es sowohl auf 4.x als auch auf 5.x abzielt?
Mason G. Zhwiti
1
@Mason - unsafe_unretainedwird sowohl in iOS 4.x als auch in 5.0 unterstützt, sodass Sie abwärtskompatibel sind. Wenn Sie nur eine Version 5.0 erstellt haben, können Sie zu wechseln weak, um die zusätzliche Sicherheit zu nutzen, die Sie erhalten.
Brad Larson
Ich habe unsafe_unretained versucht, es hat trotzdem funktioniert. Ich habe jedoch viele Warnungen erhalten wie '"** __NSAutoreleaseNoPool (): Objekt 0x564bd90 der Klasse __NSArrayM wurde automatisch freigegeben, ohne dass ein Pool vorhanden war - nur undicht" *', das ist normal?
fünfter
1
@fifth - Das ist ein völlig unabhängiges Problem. Sie führen etwas in einem Hintergrundthread aus, ohne dass ein Autorelease-Pool vorhanden ist. Manuell erstellte Threads haben keinen eigenen Autorelease-Pool, daher müssen Sie einen selbst erstellen @autoreleasepool(unter ARC, NSAutoreleasePool für ältere Implementierungen mit manuellem Referenzzähler).
Brad Larson
@Brad, das ist hilfreich, Warnungen sind weg, ich habe mehrere performSelectorInBackground-Aufrufe erhalten.
fünfter
11

Wenn Sie nur schwache Referenzen für zusätzliche Sicherheit verwenden, rufen Sie die neuen Laufzeitfunktionen manuell auf, wenn sie verfügbar sind, und greifen Sie auf eine einfache Zuweisung von __unsafe_unretainedVariablen zurück, wenn nicht.

ZWRCompatibility.h wird dies etwas vereinfachen.

rpetrich
quelle
10

Dank der Kompatibilitätsbibliothek PLWeakCompatibilty von Mike Ash können Sie __weak jetzt auch unter iOS 4.x einfach verwenden.

Es ist unglaublich einfach zu konfigurieren und erfordert keine zusätzlichen Überlegungen oder Anstrengungen über 5.x.

nschum
quelle