复制数组 - 糟糕的设计?

时间:2012-04-17 10:48:48

标签: iphone objective-c ios nsmutablearray nsarray

我从斯坦福iTunes学习Objective-C,我想知道如何在没有初始化的情况下将NSMutableArray复制到NSArray。我的意思是:

这是对的吗? “懒惰的初始化”。

-(void)copyAnArray:(NSMutableArray*)listOfElements {
    if(privateElementsLists == nil)
        privateElementsLists = [[NSArray alloc] initWithArray:listOfElements copyItems:YES];
    else
        privateElementsLists = listOfElements;
}

这是一个糟糕的设计吗? 我想在一个类中将对象添加到可变数组中,然后当我完成将整个NSMutableArray复制到NSArray时。

另一个问题:为什么我在使用initWithArray时必须使用copyItems:YES?什么是深层复制?

2 个答案:

答案 0 :(得分:2)

您可以使用initWithArray将可变数组复制到新数组:或者这样:

privateElementsLists = [NSArray arrayWithArray:listOfElements];

然后你要创建一个新数组,其中每个元素都是原始数组中的相同对象。如果你写:

privateElementsLists = [NSArray arrayWithArray:listOfElements copyItems:YES];

然后新数组为每个元素提供原始数组中元素的副本。它们不是同一个对象而是副本。当然,这些对象必须能够响应复制。

你甚至可以这样做:

privateElementsLists = (NSArray*) listOfElements ;

然后数组与原始数组完全相同。这里没有新阵列。但是,当您使用NSArray指针类转换它时,您可以使用它,就好像它是NSArray而不是NSMutableArray。如您所知,每个NSMutableArray都是NSArray(继承类)。

答案 1 :(得分:2)

正如Joseph DeCarlo所说,如果您唯一要做的就是在一个地方创建阵列以便在其他地方使用它,则无需将NSMutableArray复制到NSArray。例如,此语句有效:

NSArray* newArray = [NSMutableArray array];

或在代码中:

-(NSArray*)returnAnArray
{
    NSMutableArray* editableArray = [NSMutableArray array];
    [editableArray addObject:[[NSObject alloc] init]]; //an exemplary object added to the array
    return editableArray;
}

然而,在某些特定情况下,将NSMutableArray投射到NSArray可能不安全,例如如果原始数组存储在实例变量中。如果同时枚举返回的数组,则向/从该数组添加或删除对象可能会导致崩溃。例如:

-(void)createArray
{
    self->editableArray = [NSMutableArray array]; // instance variable: NSMutableArray* editableArray
}

-(void)addObjectToArray
{
    [self->editableArray addObject:[[NSObject alloc] init]];
}

-(NSArray*)getArray
{
    return self->editableArray;
}

-(void)enumerateArray
{
    for(NSObject obj in [self getArray])
    {
        // do something with obj
    }
}

如果addObjectToArrayenumerateArray同时被调用(例如来自后台线程),则应用程序将崩溃,因为基础数组在枚举时正在发生变化。它以NSArray*的形式返回并不重要。在这种情况下,您需要添加@synchronized以同步多个线程对同一对象的访问,或者按照建议使用arrayWithArray:复制整个数组。但请注意,文档没有说明arrayWithArray:是否是线程安全的,所以我会在@synchronized的调用周围添加arrayWithArray: