Setze ich bei Verwendung von ARC die Eigenschaften im Dealloc auf Null?

125

Ich versuche, die automatische Referenzzählung in iOS 5 zu lernen. Jetzt sollte der erste Teil dieser Frage einfach sein:

  1. Ist es richtig, dass ich bei Verwendung von ARC KEINE expliziten Release-Property-Anweisungen in meinen Dealloc schreiben muss? Mit anderen Worten, ist es wahr , dass die folgenden Fälle nicht eine explizite dealloc braucht?

    @interface MyClass : NSObject
    @property (strong, nonatomic) NSObject* myProperty;
    @end
    
    @implementation MyClass
    @synthesize myProperty;
    @end
  2. Meine nächste und wichtigere Frage stammt aus einer Zeile im Dokument " Übergang zu ARC-Versionshinweisen" :

    Sie müssen keine Instanzvariablen freigeben (können dies auch nicht), müssen jedoch möglicherweise [self setDelegate: nil] für Systemklassen und anderen Code aufrufen, der nicht mit ARC kompiliert wurde.

    Dies wirft die Frage auf: Woher weiß ich, welche Systemklassen nicht mit ARC kompiliert wurden? Wann sollte ich meinen eigenen Dealloc erstellen und explizit stark beibehaltene Eigenschaften auf Null setzen? Sollte ich davon ausgehen, dass alle in Eigenschaften verwendeten NS- und UI-Framework-Klassen explizite Freigaben erfordern?

Es gibt eine Fülle von Informationen zu SO und anderswo zu den Praktiken der Freigabe des Backing Ivar einer Eigenschaft bei Verwendung der manuellen Referenzverfolgung, aber relativ wenig dazu bei Verwendung von ARC.

emfurry
quelle

Antworten:

197

Kurze Antwort : Nein, Sie müssen keine Eigenschaften deallocunter ARC löschen.

Lange Antwort : deallocSelbst bei der manuellen Speicherverwaltung sollten Sie niemals Eigenschaften auslöschen .

In der MRR sollten Sie Ihre Ivars freigeben . Das Ausgleichen von Eigenschaften bedeutet, dass Setter aufgerufen werden, die möglicherweise Code aufrufen, den sie nicht berühren sollten dealloc(z. B. wenn Ihre Klasse oder eine Unterklasse den Setter überschreibt). Ebenso kann es zu KVO-Benachrichtigungen kommen. Das Loslassen des Ivar vermeidet stattdessen diese unerwünschten Verhaltensweisen.

In ARC gibt das System automatisch alle Ivars für Sie frei. Wenn dies alles ist, müssen Sie nicht einmal implementieren dealloc. Wenn Sie jedoch Nicht-Objekt-Ivars haben, die eine spezielle Behandlung benötigen (z. B. zugewiesene Puffer, die Sie benötigen free()), müssen Sie sich dennoch mit diesen befassen dealloc.

Wenn Sie sich selbst als Delegat eines Objekts festgelegt haben, sollten Sie diese Beziehung deaktivieren dealloc(hier geht es um das Aufrufen [obj setDelegate:nil]). Der Hinweis dazu für Klassen, die nicht mit ARC kompiliert wurden, ist ein Hinweis auf schwache Eigenschaften. Wenn die Klasse ihre delegateEigenschaft explizit als markiert, müssen weakSie dies nicht tun, da die Natur schwacher Eigenschaften bedeutet, dass sie für Sie nicht berücksichtigt werden. Wenn die Eigenschaft jedoch markiert assignist, sollten Sie sie in Ihrer deallocnicht löschen , da sonst die Klasse mit einem baumelnden Zeiger belassen wird und wahrscheinlich abstürzt, wenn sie versucht, ihrem Delegaten eine Nachricht zu senden. Beachten Sie, dass dies nur für nicht beibehaltene Beziehungen gilt, z. B. für Delegierte.

Lily Ballard
quelle
2
Das macht Sinn! Lassen Sie mich dies jedoch fragen: Ein häufiges Szenario ist, dass ich eine MyController : UIViewControllerKlasse habe, die eine UIView erstellt und besitzt und auch den Delegaten der Ansicht auf sich selbst setzt. Es ist der alleinige Inhaber dieser Ansicht. Wenn der Controller freigegeben wird, sollte auch die Ansicht freigegeben werden. Ist es dann wichtig, ob der Delegatenzeiger baumelt?
emfurry
4
@emfurry: Dies ist wahrscheinlich nicht der Fall, da die Ansicht selbst zum Zeitpunkt des Absterbens Ihres Ansichtscontrollers nicht in der Ansichtshierarchie enthalten sein und nichts tun sollte, aber es ist am besten, keine Annahmen zu treffen. Was ist, wenn die asynchron geplante Arbeit der Ansicht später ausgeführt werden soll und die Ansicht selbst ihren Ansichtscontroller um kurze Zeit überlebt (z. B. weil die asynchrone Arbeit die Ansicht vorübergehend beibehält)? Es ist am besten, den Delegierten aus Sicherheitsgründen einfach auszuschalten. Wenn es sich bei der fraglichen Ansicht um eine handelt UIWebView, wird in den Dokumenten ausdrücklich angegeben, dass Sie den Delegaten ausschließen müssen.
Lily Ballard
3
@zeiteisen: Nein. Entspricht unsafe_unretainedgenau einer assignEigenschaft und ist das normale Verhalten für delegierte Beziehungen unter MRR. Diese müssen herausgerechnet werden.
Lily Ballard
4
Ich bin nicht mit der Aussage einverstanden, keine Setter im Dealloc mit MRC zu verwenden. Apple empfiehlt es nicht, aber sie tun es auch in ihrem Code. Sie können tatsächlich neue Probleme erstellen, indem Sie den Setter nicht verwenden. Es gibt mehrere große Diskussionen darüber. Was wichtig ist, ist, den Setter richtig zu schreiben (er muss sich korrekt verhalten, wenn Sie ihm einen Nullwert übergeben) und manchmal die Reihenfolge der Freigabe zu beobachten.
Sulthan
7
@Sulthan: Ob Setter in Dealloc verwendet werden sollen oder nicht, ist eine riesige Dose Würmer, aber meine Position läuft im Wesentlichen darauf hinaus: Sie möchten so wenig Code wie möglich in Dealloc aufrufen. Setter neigen dazu, Nebenwirkungen einzuschließen, entweder durch Überschreiben in Unterklassen oder über KVO oder andere Mechanismen. Nebenwirkungen wie Dealpoc sollten besonders vermieden werden. Wenn Sie möglicherweise einen Methodenaufruf aus dem Dealloc entfernen können, sollten Sie dies tun. Dies wird vereinfacht durch: Rufen Sie keine Setter im Dealloc an.
Lily Ballard
2

Nur um die gegenteilige Antwort zu geben ...

Kurze Antwort : Nein, Sie müssen deallocunter ARC keine automatisch synthetisierten Eigenschaften ausschließen . Und Sie müssen den Setter nicht für diejenigen in verwenden init.

Lange Antwort : Sie solltendealloc auch unter ARC keine benutzerdefinierten synthetisierten Eigenschaften verwenden . Und Sie sollten den Setter für diejenigen in verwenden init.

Der Punkt ist, dass Ihre benutzerdefinierten synthetisierten Eigenschaften in Bezug auf die Aufhebung sicher und symmetrisch sein sollten.

Ein möglicher Setter für einen Timer:

-(void)setTimer:(NSTimer *)timer
{
    if (timer == _timer)
        return;

    [timer retain];
    [_timer invalidate];
    [_timer release];
    _timer = timer;
    [_timer fire];
}

Ein möglicher Setter für eine Bildlaufansicht, eine Tabellenansicht, eine Webansicht, ein Textfeld, ...:

-(void)setScrollView:(UIScrollView *)scrollView
{
    if (scrollView == _scrollView)
        return;

    [scrollView retain];
    [_scrollView setDelegate:nil];
    [_scrollView release];
    _scrollView = scrollView;
    [_scrollView setDelegate:self];
}

Ein möglicher Setter für eine KVO-Eigenschaft:

-(void)setButton:(UIButton *)button
{
    if (button == _button)
        return;

    [button retain];
    [_button removeObserver:self forKeyPath:@"tintColor"];
    [_button release];
    _button = button;
    [_button addObserver:self forKeyPath:@"tintColor" options:(NSKeyValueObservingOptions)0 context:NULL];
}

Dann müssen Sie nicht für jeden Code duplizieren dealloc, didReceiveMemoryWarning, viewDidUnload, ... und Ihr Eigentum sicher öffentlich bekannt gemacht. Wenn Sie sich Sorgen über Null-Out-Eigenschaften gemacht haben dealloc, ist es möglicherweise an der Zeit, Ihre Setter erneut zu überprüfen.

Cœur
quelle