2013-08-12 16 views
6

Ho letto altri argomenti a riguardo, ma sono comunque perso.Come implementare correttamente mutableCopyWithZone e copyWithZone

Voglio creare 2 tipi di oggetti, uno immutabile con solo proprietà "readonly" e uno mutabile con proprietà solo "readwrite".

Consente di chiamarli EXCar e EXMutableCar.

EXCar è una sottoclasse di NSObject e EXMutableCar è una sottoclasse di EXCar.

ExCar avrà nella sua interfaccia

@property (nonatomic, strong, readonly) NSString *name; 

EXMutableCar avrà nella sua interfaccia

@property (nonatomic, strong) NSString *name; 

Così ho "aperto" le proprietà di EXCar quando uso la sua subclasse EXMutableCar. E poi è mutabile. Il problema è di copiare correttamente tra di loro.

ho implementato mutableCopyWithZone in EXCar:

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar *mutableCopy = [[EXMutableCar allocWithZone:zone] init]; 
    mutableCopy.name = _name; 

    return mutableCopy; 
} 

Prima domanda, è il buon modo per farlo? (Voglio ingoiare la copia)

Il problema è con copyWithZone. Dal momento che le proprietà di EXCar sono di sola lettura Non riesco a creare né in EXCar, né in EXMutableCar una nuova istanza di EXCar e riempire le sue proprietà come questa:

- (id)copyWithZone:(NSZone *)zone { 
    EXCar *copy = [[EXCar allocWithZone:zone] init]; 
    copy.name = _name; // This can't work... 

    return copy; 
} 

E io in realtà non vogliono fare un "init" metodo con 15 proprietà da passare (di sicuro, EXCar è un esempio, le classi reali sono piene di molte proprietà). E normalmente vengono avviati dal messaggio JSON dal server, quindi non hanno bisogno di un metodo init complicato.

La seconda domanda è così, come fare una copiaWithZone che mantiene la mia classe immutabile?

Grazie per il vostro aiuto :)

risposta

9

Codice:

// EXCar.h 
#import <Foundation/Foundation.h> 

@interface EXCar : NSObject <NSCopying, NSMutableCopying> 

@property (nonatomic, strong, readonly) NSString* name; 

@end 

// EXCar.m 
#import "EXCar.h" 
#import "EXMutableCar.h" 

@implementation EXCar 

- (id)copyWithZone:(NSZone *)zone { 
    EXCar* car = [[[self class] allocWithZone:zone] init]; 
    car->_name = [_name copyWithZone:zone]; 
    return car; 
} 

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar* mutableCar = [[EXMutableCar allocWithZone:zone] init]; 
    mutableCar.name = [_name mutableCopyWithZone:zone]; 
    return mutableCar; 
} 

@end 

// EXMutableCar.h 
#import "EXCar.h" 

@interface EXMutableCar : EXCar 

@property (nonatomic, strong) NSString* name; 

@end 

// EXMutableCar.m 
#import "EXMutableCar.h" 

@implementation EXMutableCar 

@synthesize name = _mutableName; 

- (id)copyWithZone:(NSZone *)zone { 
    EXMutableCar* car = [super copyWithZone:zone]; 
    car->_mutableName = [_mutableName copyWithZone:zone]; 
    return car; 
} 

- (id)mutableCopyWithZone:(NSZone *)zone { 
    EXMutableCar* car = [super mutableCopyWithZone:zone]; 
    car->_mutableName = [_mutableName mutableCopyWithZone:zone]; 
    return car; 
} 

Spiegazione:

  • EXCar interfaccia implementa i protocolli "copiare";
  • La sottoclasse EXMutableCar sovrascrive la stessa proprietà, rendendola readwrite.

prima cosa EXMutableCar realizzazione: @synthesize name manualmente perché Xcode ci dà un avvertimento, dal momento che abbiamo la stessa proprietà (ma con diversa specificatore di accesso) nel nostro superclasse.

Nota che avrebbe potuto dare lo stesso nome alla nostra variabile di istanza, come _name, ma è importante capire che dichiariamo in sottoclasse una variabile diversa , poiché _name dalla superclasse è inaccessibile per noi.

Avanti, di Apple documentazione afferma:

Se una sottoclasse eredita NSCopying dalla sua superclasse e dichiara variabili di istanza supplementari, la sottoclasse deve ignorare copyWithZone: per gestire correttamente le proprie variabili di istanza, invocando implementazione della superclasse prima.

stesso per NSMutableCopying:

Se una sottoclasse eredita NSMutableCopying dalla sua superclasse e dichiara variabili di istanza supplementari, la sottoclasse deve ignorare mutableCopyWithZone: per gestire correttamente le proprie variabili di istanza, invocando l'implementazione del superclasse prima.

Noi facciamo dichiarano variabili di istanza aggiuntivi, in modo che non utilizzano tali metodi nel nostro sottoclasse pure.

Risultato:

EXCar* car = [[EXCar alloc]init]; // car.name is (null) 
EXCar* carCopy = [car copy]; // we can do this 
EXMutableCar* mutableCar = [car mutableCopy]; // and this 
mutableCar.name = @"BMW"; 
car = [mutableCar copy]; // car.name is now @"BMW" 
EXMutableCar* anotherMutableCar = [car mutableCopy]; //anotherMutableCar.name is @"BMW" 
+0

Copia sottoclasse mutevole deve restituire la versione immutabile, per esempio EXCar, non EXMutableCar. Ciò è particolarmente importante se le classi implementano l'uguaglianza personalizzata quando l'hash potrebbe dipendere da alcuni valori mutabili (in sottoclassi mutabili), ecco perché, ad esempio, NSDictionary copia le sue chiavi, si aspetta che gli oggetti immutabili tornino con un hash immutabile. –

Problemi correlati