2009-07-01 3 views
13

Wenn Klasse A Klasse B und Klasse A ist Delegat Klasse B, ist es in Ordnung, wenn der Delegat auf Null in Dealloc der Klasse B festgelegt ist ? Ich habe Code gesehen, der gewöhnlich den Delegierten innerhalb der Deallok der Klasse A auf Null zurückstellt, aber ich war mir nicht sicher, ob es den einen oder anderen Unterschied macht.Sollten Sie den Delegaten auf Null in der Klasse mit dem Delegaten oder in der Klasse selbst setzen

z.B. Dies ist die übliche Art und Weise:

// somewhere in class A 

- (void) someFunc { 
    self.b = [[B alloc] init]; 
    self.b.delegate = self; 
} 

- (void) dealloc { 
    self.b.delegate = nil; 
    [self.b release]; 
} 
+2

'self.b = [[Bzuordnung] init];' Sie sollten nie 'self'on LHS verwenden, wenn Sie' alloc' auf RHS verwenden, wenn '@ property' für' b' beibehalten wird. Justus wollte hinzufügen. – thesummersign

+0

@geekay, warum ist das? –

+0

das war während nicht-arc – thesummersign

Antwort

15

Ja, Sie sollten die classB des Delegierten-Eigenschaft auf null in classA der dealloc gesetzt.

Es handelt sich nicht um ein Speicherverwaltungsproblem, da die Delegate-Eigenschaften als Zuweisen, Nicht beibehalten gekennzeichnet sein sollten, um Retain-Zyklen zu vermeiden (andernfalls wird Dealloc nie aufgerufen). Das Problem besteht darin, dass Klasse B andernfalls möglicherweise die Klasse A anruft, nachdem sie freigegeben wurde.

Wenn beispielsweise Klasse B einen Delagate-Aufruf hat, um "versteckt zu sein", und Klasse B wird direkt nach KlasseA freigegeben wird, würde es die bereits freigegebene KlasseA melden, die einen Absturz verursacht.

Und denken Sie daran, Sie können nicht immer die Dealloc-Reihenfolge garantieren, besonders wenn sie automatisch freigegeben sind.

Also ja, nil die Delegate-Eigenschaft in Dealloc der KlasseA.

+1

+1 Guter Punkt über B möglicherweise Messaging A. Das ist am wahrscheinlichsten in einem Multi-Thread-Szenario, aber Sie wissen nie. Dies ist eine großartige Anwendung für __weak-Referenzen, wenn Sie GC verwenden. Ich denke, die Delegierten sollten immer einen schwachen neuen Code haben. –

+0

yup ich wurde in einer Multithread-App gebissen – marchinram

8

Soweit ich weiß, sein bewährtes Verfahren (assign) ein Delegierter, so dass Sie auf behalten Zählungen für Situationen zirkuläre Referenzen vermeiden, genau wie diesen. Wenn Sie die Eigenschaft richtig eingerichtet haben, das heißt:

@property (assign) id<BDelegate> delegate; 

Sie sollten keine Speicherverwaltung in der dealloc ausführen müssen, da der Beibehaltungszähler nicht angestoßen wird, wenn Sie self.b.delegate rufen = self ; - Im Gegensatz zur Verwendung (beibehalten) oder (Kopie)

Sinn machen? Es wäre in Ordnung, den Delegierten auf null zu setzen, aber was ist der Punkt?

+0

+1 Das ist richtig, Delegierten sollten nie wirklich beibehalten werden. Das ist eine klassische Ursache für Retain-Zyklen, da der Delegierte normalerweise das delegierende Objekt behält. –

+3

Es gibt einen Punkt beim Festlegen des Delegaten auf Null, da der Client nicht abstürzen wird, wenn er versucht, ein Delegiertenobjekt aufzurufen, das nicht mehr vorhanden ist, da es auf Null gesetzt ist. – Boon

+0

Sie entfernen die Klasse, die den Delegaten enthält ... Sie entfernen die Instanziierung der Klasse aus dem Speicher an diesem Punkt, Sie erhalten einen Speicherzugriffsfehler, wenn Sie eine Aktion für das Objekt ausführen weniger beziehen sich auf seinen Vertreter. Es sei denn, ich verpasse hier etwas ... – Josh

5

Zunächst ein paar Beobachtungen ...

  1. Sie haben vergessen [super dealloc] am Ende Ihrer eigenen dealloc Methode aufzurufen.
  2. Seit 'a' erstellt 'b', und wenn keine anderen Objekte 'b' behalten haben, gibt es keinen Sinn, den Delegierten in der -dealloc zu nieren, da 'b' ohnehin zerstört werden soll. Wenn es möglich ist, dass andere Objekte einen Verweis auf 'b' haben (was bedeutet, dass sie 'a' überleben könnten), dann setze den Delegaten auf Null.
  3. Object 'b' sollte derjenige sein, der auf seinen Delegaten in seinem eigenen aufpasst - Deall bei Bedarf. (Im Allgemeinen behält der Delegierer den Delegierten nicht.)
  4. Verwenden Sie keine Eigenschaften in -init ... und -dealloc-Methoden - Apple rät davon ab, und dies aus gutem Grund. (Nicht nur unerwartete Nebeneffekte, sondern auch unangenehmere Abstürze.)
  5. Verwenden von Eigenschaften (über die Punktsyntax), wenn Sie nicht unsichtbar zusätzliche Arbeit hinzufügen müssen. Zum Beispiel entspricht self.b.delegate = self[[self getB] setDelegate:self] - es ist nur syntaktischer Zucker, der es so aussehen lässt, als ob Sie direkt auf den ivar zugreifen, aber Sie sind es tatsächlich nicht.
  6. Die Verwendung von Eigenschaften ohne zu verstehen, was sie tun, kann zu Problemen führen. Wenn self.b den Wert behält (die Eigenschaft ist auf "assign" gesetzt), haben Sie ein Speicherleck auf Ihren Händen.

Hier ist, wie ich es wohl schreiben würde:

- (void) someFunc { 
    b = [[B alloc] init]; 
    b.delegate = self; // or [b setDelegate:self]; 
} 

- (void) dealloc { 
    b.delegate = nil; 
    [b release]; 
    [super dealloc]; 
}