2016-04-03 43 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協議正式,但你可以。