2009-07-01 8 views
13

Se la classe A utilizza la classe B e la classe A è delegata di classe B, è ok se il delegato è impostato su nil nel dealloc della classe B ? Ho visto il codice di solito resettare il delegato a zero all'interno del dealloc della classe A, ma non ero sicuro della vera differenza facendolo in un modo o nell'altro.Se si imposta il delegato su nil nella classe utilizzando il delegato o nella classe stessa

ad es. Questo è il solito modo:

// 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 = [[allocazione B] init];' non si dovrebbe mai usare 'self' su LHS se si utilizza' alloc' su RHS se '@ property' per' b' viene mantenuto. Justed voleva aggiungere. – thesummersign

+0

@geekay, perché è quello? –

+0

questo era durante il non-arco – thesummersign

risposta

15

Sì, si dovrebbe impostare la proprietà delegato del ClassB a zero in dealloc di classA.

Non è un problema di gestione della memoria, poiché le proprietà delegate devono essere contrassegnate come assign, not retain, per evitare i cicli di conservazione (altrimenti il ​​dealloc non verrà mai chiamato). Il problema è che altrimenti classB potrebbe messaggio classA dopo che è stato rilasciato.

Ad esempio, se classB ha una chiamata di delagate per dire "nascosto", e classB viene rilasciato subito dopo classA, invierà un messaggio alla classA già dealloc causando un arresto anomalo.

E ricorda, non è sempre possibile garantire l'ordine dealloc, soprattutto se sono autorizzate.

Quindi sì, niente proprietà del delegato nel dealloc della classeA.

+1

+1 Buon punto su B possibilmente messaggistica A. Molto probabilmente in uno scenario multi-thread, ma non si sa mai. Questa è una grande applicazione per __weak riferimenti se stai usando GC. Penso che i delegati dovrebbero sempre essere __tampo nel nuovo codice. –

+0

sì mi sono morso su questo in un'applicazione multithread – marchinram

8

Per quanto ne so, la sua migliore prassi di (assegnare) un delegato, in modo tale che si evita riferimenti circolari sul mantenere i conteggi per le situazioni proprio come questo. Se hai impostato la proprietà correttamente, vale a dire:

@property (assign) id<BDelegate> delegate; 

Non si dovrebbe avere per eseguire qualsiasi gestione della memoria nel dealloc, come il mantenere conteggio non viene urtato quando si chiama self.b.delegate = auto ; - a differenza dell'utilizzo (mantenimento) o (copia)

Ha senso? Sarebbe bene impostare il delegato su zero, ma qual è il punto?

+0

+1 Questo è corretto, i delegati dovrebbero praticamente mai essere mantenuti. Questa è una classica causa dei cicli di conservazione, poiché il delegato di solito conserva l'oggetto delegante. –

+3

C'è un punto nell'impostazione del delegato su nil perché se il client tenta di chiamare un oggetto delegato che non esiste più, non si bloccherà poiché è impostato su zero. – Boon

+0

Stai deallocando la classe che contiene il delegato ... rimuovi l'istanza della classe dalla memoria a quel punto, riceverai un errore di accesso alla memoria se esegui un'azione sull'oggetto, molto meno si riferiscono al suo delegato. A meno che non manchi qualcosa qui ... – Josh

5

In primo luogo, alcune osservazioni ...

  1. Hai dimenticato di chiamare [super dealloc] alla fine di un proprio metodo dealloc.
  2. Poiché 'a' creato 'b', e se nessun altro oggetto ha mantenuto 'b', non vi è alcun punto nell'annotare il delegato nello -dealloc, poiché 'b' sta per essere distrutto in ogni caso. Se è possibile che altri oggetti abbiano un riferimento a 'b' (nel senso che potrebbe sopravvivere 'a'), quindi impostare il delegato su zero.
  3. L'oggetto "b" dovrebbe essere quello che si prende cura del proprio delegato nel suo proprio -dealloc se necessario. (Generalmente, il delegante non mantiene il delegato.)
  4. Evita di utilizzare le proprietà nei metodi -init ... e -dealloc - Apple scoraggia questo e per una buona ragione. (Non solo potrebbe avere effetti collaterali imprevisti, ma può anche causare problemi più seri, più crudi.)
  5. Utilizzare le proprietà (tramite la sintassi del punto) quando non è necessario aggiungere in modo invisibile del lavoro extra. Ad esempio, self.b.delegate = self equivale a [[self getB] setDelegate:self] - è solo zucchero sintattico che fa sembrare che stai accedendo direttamente a Ivar, ma in realtà non lo sei.
  6. L'utilizzo di proprietà senza capire cosa fanno può portare a problemi. Se self.b mantiene il valore (la proprietà è impostata su "assegna"), si ha una perdita di memoria tra le mani.

Ecco come avrei probabilmente scriverlo:

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

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