2016-04-03 33 views
2

我有许多“模型”对象,其属性被定义为“只读”并在各个组件之间共享。用于创建可变副本的Objective-C模式

在某些情况下,我需要创建对象的本地副本可变(使用他们的本地可变状态)

我宁愿不落实NSMutableCopy协议被创建后,它的对象应该是一成不变的。修改后的对象可以在复制+ mutate操作后“传递”。

是否有建议的机制,或者我应该只实现一个构造函数接收“更改”参数?

例如一个对象,它解析JSON到本地类型:

@interface ImmutableObject : NSObject 
// various "readonly" properties 
... 
-(instancetype)initWithJSON:(NSDictionary *)jsonDictionary; 

@property (nonatomic, readonly) MyClass1 *prop1; 
@property (nonatomic, readonly) MyClass2 *prop2; 
... 
@property (nonatomic, readonly) NSArray<MyClass100 *> *prop100; 

@end 

@implementation 
-(instancetype)initWithJSON:(NSDictionary *)jsonDictionary { 
    self = [super init]; 
    [self parseDictionaryToNative:jsonDictionary]; 
    return self; 
} 
@end 

某处在代码:

ImmutableObject *mutated = [immutableObject mutableCopy]; // best way to accomplish this? 
// change some values... 
mutated.prop1 = ... // change the value to something new 

self.state = [mutated copy]; // save the new object 

回答

1

@spinalwrap是正确的,但在这种情况下,没有理由在存储之前创建额外的副本。 NSMutableArrayNSArray的一个子类,因此可以在任何可以使用NSArray的地方使用(这很常见)。你的也一样。在您的特定情况下,你可能会做这种方式:

MutableObject *mutated = [immutableObject mutableCopy]; // create an instance of MutableObject 

mutated.prop1 = ... // change the value to something new 

self.state = mutated; // Since `state` is an immutable type, 
         // attempts to mutate this later will be compiler errors 

这是安全的,因为你知道,这个代码块是有对象的可变版本的引用的唯一块(因为你在这里创建它)。

这就是说,一旦你创建了一个可变的子类,你现在需要考虑的是任何ImmutableObject您传递实际上可能是一个MutableObject的可能性,所以让防守副本(就像与NSArrayNSString完成,等)例如:

- (void)cacheObject:(ImmutableObject *)object { 
    // Need to copy here because object might really be a MutableObject 
    [self.cache addObject:[object copy]]; 
} 

这是通过在ImmutableObjectreturn self和实施copy,并在MutableObject实施copy作为实际副本,通常这样做是相当有效的

ImmutableObject。米

- (ImmutableObject *)copy { 
    return self; 
} 

MutableObject.m

// as in spinalwrap's example 
- (MutableObject *)mutableCopy { 
    MutableObject *instance = [MutableObject new]; 
    instance.prop1 = [self.prop1 copy]; // depends what you want here and what kind of class the properties are... do you need a deep copy? that might be a bit more work. 
    // etc... 
    return instance; 
} 

// No need to duplicate code here. Just declare it immutable; 
// no one else has a pointer to it 
- (ImmutableObject *)copy { 
    return (ImmutableObject *)[self mutableCopy]; 
} 

所以副本几乎是免费的,如果对象是不可改变的了。我说“相当有效”,因为它仍然会导致一些永不变异的可变对象的不必要拷贝。 Swift的值类型复制系统专门用于处理ObjC中的这个问题。但以上是ObjC中的常见模式。

+0

由于该类代表了一个相当大的模型,因此创建2个独立的类非常繁琐且容易出错。 我希望有一个“快速”的机制来定义一个“var”而不是“let”变量,并自动获得一个可变版本。 我已经使出原创(从原来的,而不是“自我”)返回一个实际的副本,并使用KVC来改变“只读”属性,(因为我正在改变〜2-3道具) 。 –

1

注意到NSMutableArrayNSMutableData等是不同类的比它们的不可变。因此,在这种情况下,您可能应该定义一个MutableObject类,该类具有与ImmutableObject类相同的接口(但具有可变属性),并且如果要具有可变对象,则使用该类。

MutableObject *mutated = [immutableObject mutableCopy]; // create an instance of MutableObject 

mutated.prop1 = ... // change the value to something new 

self.state = [mutated copy]; // creates an ImmutableObject 

ImmutableObject'smutableCopy实现可能是这样的:

- (MutableObject *) mutableCopy 
{ 
    MutableObject *instance = [MutableObject new]; 
    instance.prop1 = [self.prop1 copy]; // depends what you want here and what kind of class the properties are... do you need a deep copy? that might be a bit more work. 
    // etc... 
    return instance; 
} 

MutableObject'scopy方法看起来是这样的:

- (ImmutableObject *) copy 
{ 
    ImmutableObject *instance = [ImmutableObject new]; 
    instance.prop1 = [self.prop1 copy]; 
    // etc... 
    return instance; 
} 

你不会被迫使用NSMutableCopy协议正式,但你可以。