检测Array中是否已启动一个位置

时间:2009-07-03 17:24:39

标签: iphone objective-c cocoa-touch

我需要检查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的方法,以及类似的东西!

3 个答案:

答案 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中很少需要进行强制转换。它通常只会增加噪音,并可以隐藏真正的错误。由于您遇到崩溃,因此值得从此代码中删除强制转换并听取​​编译器告诉您的内容。

告诉编译器忽略一段代码的警告不会使它的潜在问题消失!