64

Ho alcune domande sulle proprietà sintetizzate in Objective-C. Segue l'elenco completo, ma la domanda di base è questa: Come fa il compilatore a garantire che gli ivars per le proprietà sintetizzate vengano rilasciati correttamente, anche se il mio codice può includere o meno metodi di rilascio in dealloc?In che modo viene rilasciata la release per le proprietà di ritenzione @synthesized?

Nota: ho deciso di non inserire questi come singoli domande perché sono così strettamente correlati e perché ci sono una manciata di domande esistenti che tocco sui singoli problemi senza realmente arrivare al cuore della questione.

domande in qualche modo simili:


Setup: Si consideri una classe con una singola proprietà:

@interface Person : NSObject 
{ 
    NSString * name; 
} 
@property (nonatomic, retain) name; 
@end 

Domanda # 1: Il caso molto semplice:

@implementation Person 
@synthesize name; 
@end 

Con questa impostazione, presumo che name uscirà automaticamente ogni volta che un oggetto Person viene rilasciato. Nella mia mente, il compilatore inserisce semplicemente [name release] nel metodo dealloc come se lo avessi digitato io stesso. È corretto?


Domanda # 2: Se scelgo di scrivere il mio metodo dealloc per questa classe, e tralascio una chiamata a [name release], sarà quella perdita?

@implementation Person 
@synthesize name; 
- (void)dealloc { [super dealloc]; } 
@end 

Domanda # 3: Se scelgo di scrivere il mio metodo dealloc per questa classe, e io includo una chiamata a [name release], volontà che si traducono in una doppia versione, dal momento che @synthesize si è già preso cura di me per me?

@implementation Person 
@synthesize name; 
- (void)dealloc { [name release]; [super dealloc]; } 
@end 

Domanda # 4: Se scelgo di scrivere il mio di accesso di proprietà per questa classe, ma io Non scrivere il mio metodo dealloc, sarà name essere trapelato?

@implementation Person 
@dynamic name; 
- (void)setName:(NSString *)newName 
{ 
    [newName retain]; 
    [name release]; 
    name = newName; 
} 
@end 

Domanda # 5: ho la sensazione che (in base all'esperienza) che nessuno degli scenari di cui sopra si tradurrà in perdite o doppio-release, dal momento che il linguaggio è stato progettato al fine di evitare loro. Questo, naturalmente, solleva la questione di "come?". Il compilatore è abbastanza intelligente da tenere traccia di ogni possibile caso? E se dovessi fare la seguente (si noti che questo è un esempio ridicolo, proprio lo scopo di illustrare il mio punto):

void Cleanup(id object) { [object release]; } 

@implementation Person 
@synthesize name; 
- (void)dealloc { Cleanup(name); } 
@end 

Would che ingannare il compilatore in aggiunta di un altro [name release] al metodo dealloc?

risposta

57

Q1:

No. @synthesize non modifica il -dealloc per voi. Devi -release il name tu stesso.

Q2:

Sì vi saranno perdite. Lo stesso motivo di Q1.

Q3:

No non lo farà doppio rilascio. Lo stesso motivo di Q1.

Q4:

Sì vi saranno perdite. Lo stesso motivo di Q1.

Q5:

No non lo farà doppio rilascio. Lo stesso motivo di Q1.


Potete controllare voi stessi sovrascrivendo -retain e -release e -dealloc riferire cosa sta succedendo.

#import <Foundation/Foundation.h> 

@interface X : NSObject {} 
@end 
@implementation X 
-(oneway void)release { 
     NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1); 
     [super release]; 
} 
-(id)retain { 
     NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1); 
     return [super retain]; 
} 
-(void)dealloc { 
     NSLog(@"Dealloc %p", self); 
     [super dealloc]; 
} 
@end 

@interface Y : NSObject { 
     X* x; 
} 
@property (nonatomic, retain) X* x; 
@end 
@implementation Y 
@synthesize x; 
- (void)dealloc { [x release]; [super dealloc]; } 
@end 

int main() { 
     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
     Y* y = [[Y alloc] init]; 
     X* x = [[X alloc] init]; 
     y.x = x; 
     [y release]; 
     [x release]; 
     [pool drain];              
     return 0; 
} 

In Q1, Q2 e Q4, l'ultimo -retainCount di x è 1, quindi c'è una perdita, e in Q3 e Q5 l'ultimo -retainCount è 0 e -dealloc è chiamato, quindi non c'è perdita.

+2

Grazie per la risposta dettagliata. Sono contento di averlo chiesto! –

+0

Molto ben spiegato! –

17

Dalle Objective-C documentation on properties:

dealloc

proprietà dichiarate fondamentalmente prendere il posto di metodo accessorio dichiarazioni; quando si sintetizza una proprietà , il compilatore crea solo metodi di accesso assenti. C'è nessuna interazione diretta con il dealloc metodo-proprietà non sono rilasciato automaticamente per voi. proprietà dichiarate, tuttavia, forniscono un modo utile per un controllo incrociato l'attuazione del metodo dealloc : si può guardare per tutte le dichiarazioni di proprietà nel file di intestazione e assicurarsi che oggetto proprietà non contrassegnati assegnare sono rilasciato e quelli contrassegnati assegnati sono non rilasciato.

Questo essenzialmente risponde a tutte le vostre domande.

+0

+1 Grazie per il link. Questo sicuramente arriva al nocciolo della questione. –

8

La regola semplice e generale: se si assegna, si conserva o si copia un oggetto, è necessario rilasciarlo.

Quando si utilizza l'impostazione semantica retain setter in un'istruzione @synthesize, si richiede al compilatore di creare per voi un setter che chiama retain sull'oggetto. Niente di più, niente di meno. E dal momento che stai mantenendo quell'oggetto (anche se è tramite codice magicamente generato automaticamente), devi rilasciarlo, e dove rilasciarlo è in -(void)dealloc.

+4

+1 Questa è una regola eccellente (e spesso citata). Molte persone (me stesso incluso, quando ho posto questa domanda) non si rendono conto che specificare "conservare" o "copiare" in una dichiarazione di proprietà è ancora valido. Penso che il problema risieda nel testo: "Ho * I * mantenuto il valore? No, il codice automagic del compilatore lo ha fatto per me. –

+1

Alcuni mesi dopo aver postato questa risposta, ne ho pubblicato uno ancora migliore, qui: http://stackoverflow.com/questions/5122786/iphone-objective-c-should-this-value-be-released/5122821#5122821 Ha un buon mnemonico. Vai a vedere. –

+0

roba buona. Spero che accada! –

2

Qualcos'altro vale la pena sapere - se si dispone di una proprietà sintetizzata, l'impostazione di tale proprietà su zero (utilizzando la sintassi del punto, ovviamente) rilascerà l'ivar per te.

Problemi correlati