2009-05-16 12 views
12

Qual è giusto? Questo:Gestione della memoria ed eseguiSelectorInBackground:

NSArray* foo = [[NSArray alloc] initWithObjects:@"a", @"b", nil]; 
[bar performSelectorInBackground:@selector(baz:) withObject:foo]; 

- (void)baz:(NSArray*)foo { 
    ... 
    [foo release]; 
} 

Oppure:

NSArray* foo = [[[NSArray alloc] initWithObjects:@"a", @"b", nil] autorelease]; 
[bar performSelectorInBackground:@selector(baz:) withObject:foo]; 

- (void)baz:(NSArray*)foo { 
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
    ... 
    [pool release]; 
} 

So che il primo funziona, ma Clang lamenta, quindi mi chiedo se c'è un modello migliore da utilizzare.

avrei "cerco solo fuori" il 2 °, ma con autoreleasing, chi sa se l'assenza di EXC_BAD_ACCESS significa che si sta facendo bene o che hai appena avuto fortuna ...

risposta

24

In primo luogo è sbagliato .

performSelectorInBackground: withObject: mantiene entrambe le barre e pippo fino a quando l'attività viene eseguita. Pertanto, dovresti autorappolarti quando lo crei e lasciare che performSelectorInBackground: withObject si occupi del resto. Vedi documentation

L'ultimo è corretto perché si autorelease pippo quando lo si crea. Il pool di autorelease creato all'interno di baz non ha nulla a che fare con la correttezza della gestione della memoria di foo. Questo pool di autorelease è necessario per gli oggetti autoreleased all'interno dell'allocazione di pool e il rilascio in baz, non tocca affatto il numero di ritenzione di foo.

+1

Oh, è proprio lì nella documentazione! Silly me. :) – lawrence

+4

Devo chiarire: è necessario creare e svuotare un pool di autorelease all'interno di -baz :, a meno che non si sappia che non verrà inviato un metodo di auto-autorizzazione all'interno. La migliore regola empirica consiste nell'assumere che ciò accada e creare/drenare un pool di autorelease, come nell'esempio 2. Ma utilizzare [pool drain], non [release pool]. –

+0

Esattamente come diceva Jim Dovey: di solito è necessario creare un pool di autorelease come per la funzione principale (vedere Guida alla programmazione dei thread). È solo importante capire che questo pool non ha nulla a che fare con la autorelease di foo. –

2

L'approccio corretto ora sarebbe infatti quello di fare:

NSArray* foo = [[[NSArray alloc] initWithObjects:@"a", @"b", nil] autorelease]; 
[bar performSelectorInBackground:@selector(baz:) withObject:foo]; 

- (void)baz:(NSArray*)foo { 
    @autoreleasepool { 
     ... 
    } 
}