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