Inizializzazione di una proprietà, notazione dot

È una ctriggers idea utilizzare la notazione dot per inizializzare le proprietà di conservazione su zero nei miei metodi init?

Con qualsiasi proprietà ordinaria come questa:

@property (nonatomic, retain) id foo; 

Dì nel mio metodo init ho impostato self.foo = nil . Il metodo sintetizzato prima rilascia o autoreleases foo (non esattamente sicuro della sottostante impementazione). È foo garantito di essere nullo prima del primo setter o della chiamata getter? O punterebbe alla spazzatura casuale a meno che non imposti esplicitamente foo = nil senza la notazione del punto?

È una ctriggers idea utilizzare la notazione dot per inizializzare le proprietà di conservazione su zero nei miei metodi init?

Sì, è una ctriggers idea.

1) L’object è già stato azzerato nella sequenza alloc + init , quindi non è necessario assegnarlo a zero. In altre parole, questa chiamata è inutile a meno che non si abbiano effetti collaterali nei propri utenti (in questa fase si dovrebbero evitare anche gli effetti collaterali in accessor).

2) Non si dovrebbe dealloc messaggi a se stessi con metodi che vengono sovrascritti mentre si trovano in stati parzialmente costruiti (es. dealloc e dealloc ).

C’è una ragione per # 2? Faccio spesso self.array = [NSMutableArray array]; nei miei metodi di init.

La ragione è che il tuo object non dovrebbe essere interessato al comportamento dell’interfaccia di class durante stati parzialmente costruiti ( init... , dealloc , finalize e many copyWithZone: implementazioni). la tua class dovrebbe essere interessata a inizializzare correttamente (come in init... ) e ripulire se stessa compresi i suoi membri (come in dealloc ) senza introdurre effetti collaterali.

considera questo esempio, che puoi creare come strumento di base per OS X:

 #import  enum { UseItTheRightWay = true -OR- false }; @interface MONObjectA : NSObject { NSMutableArray * array; } @property (nonatomic, retain) NSArray * array; @end @implementation MONObjectA @synthesize array; - (id)init { self = [super init]; if (0 != self) { NSLog(@"%s, %@",__PRETTY_FUNCTION__, self); if (UseItTheRightWay) { array = [NSMutableArray new]; } else { self.array = [NSMutableArray array]; } } return self; } - (void)dealloc { NSLog(@"%s, %@",__PRETTY_FUNCTION__, self); if (UseItTheRightWay) { [array release], array = nil; } else { self.array = nil; } [super dealloc]; } @end @interface MONObjectB : MONObjectA { NSMutableSet * set; } @end @implementation MONObjectB - (id)init { self = [super init]; if (0 != self) { NSLog(@"%s, %@",__PRETTY_FUNCTION__, self); set = [NSMutableSet new]; } return self; } - (void)dealloc { NSLog(@"%s, %@",__PRETTY_FUNCTION__, self); [set release], set = nil; [super dealloc]; } - (void)setArray:(NSArray *)arg { NSLog(@"%s, %@",__PRETTY_FUNCTION__, self); NSMutableSet * tmp = arg ? [[NSMutableSet alloc] initWithArray:arg] : nil; [super setArray:arg]; [set release]; set = tmp; } @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; [[MONObjectB new] release]; /* the tool must be named 'Props' for this to work as expected, or you can just change 'Props' to the executable's name */ system("leaks Props"); [pool drain]; return 0; } 

L’interruttore principale per commutare il comportamento in questo test è UseItTheRightWay .

Se UseItTheRightWay è vero , ci viene dato il risultato:

 2011-05-09 01:52:11.175 Props[45138:a0f] -[MONObjectA init],  2011-05-09 01:52:11.177 Props[45138:a0f] -[MONObjectB init],  2011-05-09 01:52:11.179 Props[45138:a0f] -[MONObjectB dealloc],  2011-05-09 01:52:11.179 Props[45138:a0f] -[MONObjectA dealloc],  leaks Report Version: 2.0 Process: Props [45138] < --- snip --- > Process 45138: 1581 nodes malloced for 296 KB Process 45138: 0 leaks for 0 total leaked bytes. 

E se UseItTheRightWay è falso , ci viene dato il risultato:

 2011-05-09 01:55:51.611 Props[45206:a0f] -[MONObjectA init],  2011-05-09 01:55:51.614 Props[45206:a0f] -[MONObjectB setArray:],  2011-05-09 01:55:51.615 Props[45206:a0f] -[MONObjectB init],  2011-05-09 01:55:51.617 Props[45206:a0f] -[MONObjectB dealloc],  2011-05-09 01:55:51.618 Props[45206:a0f] -[MONObjectA dealloc],  2011-05-09 01:55:51.618 Props[45206:a0f] -[MONObjectB setArray:],  leaks Report Version: 2.0 Process: Props [45206] < --- snip --- > Process 45206: 1585 nodes malloced for 297 KB Process 45206: 1 leak for 48 total leaked bytes. Leak: 0x100110970 size=48 zone: DefaultMallocZone_0x100005000 instance of 'NSCFSet', type ObjC, implemented in Foundation 0x70294ff8 0x00007fff 0x00001080 0x00000001 .O)p............ 0x00000001 0x00000000 0x00000000 0x00010000 ................ 0x707612a8 0x00007fff 0x00000000 0x00000000 ..vp............ 

Problema n. 1

L’evidente fallimento di questo esempio è la perdita, introdotta in dealloc .

Problema # 2

La seconda cosa che ti morderà è più sottile:

 -[MONObjectA init] -[MONObjectB setArray:] -[MONObjectB init] 

Che cos’è questo??? -[MONObjectB setArray:] viene chiamato prima -[MONObjectB init] ? Ciò significa che l’implementazione di MONObjectB è usata prima -[MONObjectB init] , e anche prima -[MONObjectA init] è uscito. Non va bene = \

I progetti non banali produrranno solo una serie di effetti collaterali indesiderati, comportamenti strani, perdite e così via. I progetti complessi falliranno in modi molto ovvi e molto sottili che possono essere molto difficili da rintracciare. è meglio evitare mal di testa di manutenzione su tali banali differenze scritte e scrivere le classi nel modo giusto fin dall’inizio (anche se si potrebbe fare a meno di farlo per un po ‘di tempo, senza ovvi effetti collaterali).