2013-10-31 8 views
5

Spesso si legge, che le classi immutabili possono implementare copyWithZone molto efficiente nel seguente modo:Restituisce [self retain] in copyWithZone per classi immutabili con sottoclassi mutabili veramente sicure/una buona idea?

- (id) copyWithZone:(NSZone*)zone 
{ 
    return [self retain]; 
} 

L'idea alla base che l'attuazione è ovvio: L'originale e la copia sono entrambi i casi immutabili e che avrà sempre esattamente lo stesso contenuto, quindi perché non lasciare che entrambi puntino allo stesso spazio di archiviazione mantenendo l'originale ed evitando il sovraccarico di copia.

Tuttavia, cosa succederà se è presente una sottoclasse mutabile? Con un'architettura pulita, in cui una sottoclasse non deve preoccuparsi di dettagli di implementazione della sua classe base, la sottoclasse mutabile dovrebbe andare bene per implementare copyWithZone in questo modo:

- (id) copyWithZone:(NSZone*)zone 
{ 
    MyClass* myCopy = [super copyWithZone:zone]; 
    myCopy->myMember = [myMember copyWithZone:zone]; 
    return myCopy; 
} 

Ma cosa significa tutto questo con quanto sopra implementazione della superclasse di copyWithZone? La sottoclasse è mutabile, quindi anche se la copia è immutabile, l'originale ora è mutevole, ma la sottoclasse copyWithZone grazie all'implementazione della superclasse opera su un'istanza mantenuta di se stessa: self e myCopy puntano entrambi alla stessa istanza, quindi se io successivamente cambia il valore di mutableOriginal.myMember, quindi cambierà anche immutableCopy.myMember, che è semplicemente sbagliato.

Quindi le classi immutabili non dovrebbero implementare meglio copyWithZone nel modo seguente?

- (id) copyWithZone:(NSZone*)zone 
{ 
    if([[self class] isMemberOfClass:[MyBaseClass class]]) 
     return [self retain]; 
    else 
    { 
     MyBaseClass* myCopy = [[self alloc] init]; 
     myCopy->myBaseMember = [myBaseMember copyWithZone:zone]; 
     return myCopy; 
    } 
} 
+2

Non proprio. Non penso che si debba implementare 'copia' seguendo uno degli approcci elencati. La copia è * molto * intrinseca. È meglio non chiamare '[super copia]' ma assegnare una nuova istanza pulita, se necessario. –

risposta

3

La soluzione migliore sarebbe quella di avere un initWithMyImmutableObject initialiser nella superclasse immutabile. La vostra sottoclasse può poi basta implementare NSCopying con

- (id) copyWithZone:(NSZone*)zone { 
    return [[[self superclass] alloc] initWithMyImmutableObject:self] 
} 

In questo modo la copia reale di proprietà è fatto in un metodo di vostra superclasse, che ha accesso a tutti i membri privati ​​che hanno bisogno di essere copiati.