2010-04-02 7 views
10

Qui potrebbe mancare qualcosa di ovvio, ma sto implementando NSCopying su uno dei miei oggetti. Quell'oggetto ha variabili di istanza private che non sono esposte tramite getter, poiché non dovrebbero essere utilizzate al di fuori dell'oggetto.Le migliori pratiche per copiare le istanze private vars con NSCopying

Nella mia implementazione di copyWithZone:, ho bisogno di allocare/init la nuova istanza, ma anche di impostare il suo stato in modo che corrisponda all'istanza corrente. Posso ovviamente accedere allo stato privato corrente dall'interno di copyWithZone:, ma non posso impostarlo nel nuovo oggetto, perché non ci sono accessori per quello stato.

Esiste un metodo standard per mantenere intatto la privacy dei dati?

Grazie.

risposta

8

In primo luogo, si dovrebbe sempre avere getter, anche se sono private. Il tuo oggetto dovrebbe accedere solo ai propri ivars usando gli accessor (eccetto in un numero molto piccolo di casi). Ciò ti farà risparmiare molta sofferenza sulla gestione della memoria.

In secondo luogo, il suggerimento di Alex di usare -> è un approccio standard, anche se questo viola la regola dei getter sopra. Esistono un numero limitato di eccezioni a tale regola e la copia è una delle. Usare i setter privati ​​qui è ancora ragionevole (e lo facevo esclusivamente in questo modo), ma ho trovato per vari motivi che l'utilizzo di -> spesso funziona più pulito.

Fare molta attenzione a correggere la gestione della memoria. Se hai bisogno di chiamare il numero [super copyWithZone:], allora dovresti anche leggere le complessità di NSCopyObject() e di come ti influisce anche se non lo usi da solo. Ne ho discusso a lungo in "NSCopyObject() considered harmful."

+0

Grazie per la menzione di accessors privati ​​e pericoli di NSCopyObject. –

+0

Non sono sicuro in che modo l'accesso di sola lettura facilita la gestione della memoria? Se non lo usi con 'assign' o' retain', non fa differenza se usi getter o la variabile direttamente. – Hemant

+0

@Hemant, perché il chiamante non dovrebbe aver bisogno di stare attento se la proprietà è attualmente (o in futuro) in sola lettura o meno. Quella non è la faccenda del chiamante, e potrebbe cambiare nel tempo, e quindi avresti bisogno di dare la caccia a ogni pezzo di codice che lo ha fatto in modo errato. Attenendosi a semplici regole, gli errori diventano ovvi. Quando dici "oh, tranne quando mi capita di sapere che al momento è ok" allora ti stai aprendo per problemi di manutenzione. –

5

È possibile accedere direttamente alle variabili di istanza della copia. Si utilizza la stessa sintassi di dereferenziazione del puntatore che si utilizzerà con una struttura. Così, per esempio, se la classe è questa:

@interface MyCopyableClass : NSObject { 
    int anInstanceVariable; 
} 
@end 

Si può fare questo:

- (id)copyWithZone:(NSZone *)zone { 
    MyCopyableClass *theCopy = [[[self class] allocWithZone:zone] init]; 
    theCopy->anInstanceVariable = anInstanceVariable; 
    return theCopy; 
} 
1

Un'opzione è creare un inizializzatore personalizzato che accetta i valori privati ​​di iVar. Così si crea piace:

-(id) initWithPropertyOne:(SomeClass *) anObject andPropertyTwo:(SomeClass *) anotherObject; 

Quando si crea un'istanza della copia, basta usare l'inizializzatore personalizzato.

Problemi correlati