我需要检查NSArray
中的具体位置,看看它们是否已经初始化,但我遇到了麻烦。我尝试执行以下操作,但它会导致我的应用程序崩溃!
if ((NSMutableArray *)[arrAllBlocks objectAtIndex:iLine] == nil)
{
[arrAllBlocks insertObject:[[NSMutableArray alloc] init] atIndex:iLine];
}
NSMutableArray *columArray = (NSMutableArray *)[arrAllBlocks
objectAtIndex:iLine];
[columArray insertObject:newBlock atIndex:iColumn];
最好的做法是什么?我已经尝试了一些类似isValid
的方法,以及类似的东西!
答案 0 :(得分:5)
你有几个选择:
选项1:使用NSNull
的实例预填充数组,然后使用Dave DeLong在his answer中提供的代码。
选项2:(类似于#1)使用NSMutableArray
的实例预填充数组,然后根本没有额外的代码。 (如果你要预先填写,你也可以这样做。)
选项3:不要预先填充数组,而是根据需要动态插入项目。如果第一个iLine
接近最大值,则这与预填充几乎相同:
while([arrAllBlocks count] <= iLine)
{
[arrAllBlocks addObject:[NSMutableArray arrayWithCapacity:0]];
}
NSMutableArray *columArray = (NSMutableArray *)[arrAllBlocks
objectAtIndex:iLine];
[columArray insertObject:newBlock atIndex:iColumn];
选项4 :使用字典维护NSMutableArrays
列表:
NSString *key = [NSString stringWithFormat:@"%d", iLine];
NSMutableArray *columnArray = [dictAllBlocks objectForKey:key];
if (columnArray == nil)
{
columnArray = [NSMutableArray arrayWithCapacity:0];
[dictAllBlocks setObject:columnArray forKey:key];
}
[columArray insertObject:newBlock atIndex:iColumn];
如何选择:
如果iLine
的最大值不是很大,我会选择#2。少数NSMutableArrays
初始化为零容量将占用很少的内存。
如果iLine
的最大值很大,但您希望它被稀疏地访问(即,只会访问iLine
的几个值),那么您应该选择# 4。这将使您不必使用永远不会被使用的对象填充NSMutableArray
。转换字典的字符串值键的开销将小于创建所有这些空格的开销。
如果您不确定,请尝试每个选项并对其进行分析:测量您的内存使用情况和执行所需的时间。如果这些选项都不起作用,您可能需要探索更复杂的解决方案,但只有在必要时才这样做。
注意事项:
您发布的原始代码在以下行中有内存泄漏:
[arrAllBlocks insertObject:[[NSMutableArray alloc] init] atIndex:iLine];
您在此初始化的NSMutableArray
对象永远不会被释放。当您致电[[NSMutableArray init] alloc]
时,会创建一个全新的对象(引用计数为1)。然后insertObject
方法将新对象添加到arrAllBlocks
,将retains
添加到arrAllBlocks
(将其保留计数增加到2)。稍后,当您释放release
时,新数组将发送[NSMutableArray arrayWithCapacity:0]
消息,但这只会将其保留计数再次减少为1。此时,它将一直存在于RAM中,直到您的程序退出。
这里最好的办法是使用NSMutableArray
代替(正如我在我的例子中所做的那样)。这将返回一个新的autoreleased
,与您的代码相同,但此实例已经为arrAllBlocks
。这样,{{1}}可以获得新对象的所有权,并且您可以确定它将在适当时发布。
答案 1 :(得分:4)
你做不到。 NSArray(及其子类NSMutableArray)不允许您将nil插入数组中。这在文档中清楚地概述了。
如果由于某种原因,您需要在数组中包含“空”值,那么您应该插入[NSNull null]并测试它。来自文档:“NSNull类定义了一个单独的对象,用于表示集合对象中的空值(不允许使用nil值)。”
更新:
这意味着您可以非常简单地将代码更改为:
if ([[arrAllBlocks objectAtIndex:iLine] isEqual:[NSNull null]]) {
[(NSMutableArray *)arrAllBlocks insertObject:[NSMutableArray array] atIndex:iLine];
}
NSMutableArray *columnArray = (NSMutableArray *)[arrAllBlocks objectAtIndex:iLine];
[columnArray insertObject:newBlock atIndex:iColumn];
答案 2 :(得分:1)
要检查NSNull,您可以简单地与指针进行比较,因为它是一个Singleton:
if ([NSNull null] == [arrAllBlocks objectAtIndex:iLine]) {
[arrAllBlocks insertObject:[NSMutableArray array] atIndex:iLine];
}
NSMutableArray *columnArray = [arrAllBlocks objectAtIndex:iLine];
[columnArray insertObject:newBlock atIndex:iColumn];
我也删除了难看的演员阵容。 Objective-C中很少需要进行强制转换。它通常只会增加噪音,并可以隐藏真正的错误。由于您遇到崩溃,因此值得从此代码中删除强制转换并听取编译器告诉您的内容。
告诉编译器忽略一段代码的警告不会使它的潜在问题消失!