NSCopying自定义对象数组

时间:2013-03-18 23:07:21

标签: ios objective-c arrays nscopying

我有一个管理我所有列表的Singleton对象。我们称之为ListStore。

ListStore有一个可变数组,用于存储列表。

@interface ListStore : NSObject
    @property (nonatomic, copy) NSMutableArray *lists; // an array of List objects
end

列表有一个可变数组,用于存储事物。

@interface Wanderlist : NSObject <NSCoding, NSCopying>
    @property (nonatomic, copy) NSMutableArray *things; // an array of Thing objects
@end

任何时候,后台进程都可以通过ListStore循环并处理所有列表,而用户可能正在与List进行交互。

为了防止“对象在被枚举时被突变”类型错误,我这样做:

// all of this is in a background thread
NSArray *newLists = [[ListStore sharedStore] lists] copy];

for (List *list in newLists) {
    // yay, no more crashes, because I'm enumerating over a copied object, so the user
    // can do whatever they want while I'm here

    for(Thing *thing in list.things) {
        // oh crap, my copy and the original object both reference the same list.things,
        // which is why i'm seeing the 'mutation while enumerating" errors still
        ...
    }
}

我原本以为是因为我复制了newLists所有成员都会被正确复制。我现在明白不是这样的:我仍然看到“对象在枚举时发生了变异”错误,但这一次发生在list.things上。

我可以在我的设置中使用NSCopying,以便在我说:

[[ListStore sharedStore] copy];

它会在copyWithZone:上调用Lists,因此我可以在copyWithZone: thingscopyWithZone:

我试图像这样设置它,但NSArray *newList = [list.things copy]没有被调用。

我知道我可以简单地说{{1}}但我希望至少能更好地了解NSCopying。

1 个答案:

答案 0 :(得分:3)

在提交此问题之前,我点击了SO相关问题列表中的问题,找到了我的解决方案。

想到发布我的解决方案并没有什么坏处。

而不是:

NSArray *newLists = [[ListStore sharedStore] lists] copy];

我必须这样做:

NSArray *newLists = [[NSArray alloc] initWithArray:[[ListStore sharedStore] lists] copyItems:true];

来自the NSArray docs

- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag
flag: 
If YES, each object in array receives a copyWithZone: message to create a copy of the object—objects must conform to the NSCopying protocol. In a managed memory environment, this is instead of the retain message the object would otherwise receive. The object copy is then added to the returned array.

一旦我使用了initWithArray:copyItems:,它会自动将copyWithZone发送到我的所有List对象,然后我就可以在list.things上手动执行copyWithZone。