2009-07-03 43 views
1

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

回答

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方法将该新对象添加到arrAllBlocksretains它(将其保留计数增加到2)。稍后,当您发布arrAllBlocks时,新阵列将发送release消息,但这只会将其保留次数再次减少为1。在那个时候,它会一直存在于RAM中,直到你的程序退出。

这里要做的最好的事情是使用[NSMutableArray arrayWithCapacity:0]来代替(正如我在我的例子中所做的那样)。这将返回一个新的NSMutableArray,与您的代码一样,但此实例已为autoreleased。这样,arrAllBlocks可以获得新对象的所有权,并且您可以确保它将在适当时候发布。

4

你不能。 NSArray(及其子类NSMutableArray)不允许你在数组中插入nil。这在文档中已清楚地概述。

如果出于某种原因需要在数组中有“空”值,那么应该插入[NSNull null],然后测试它。从文档:“NSNull类定义了一个单独的对象,用于表示集合对象中的空值(不允许有零值)。”

UPDATE:

这意味着你可以很简单地改变你的代码如下:

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]; 
+0

Hummm,好的! 但是我尝试了你所说的,但还没有正常工作=/ 我需要这个,因为arrAllBlocks中的对象数目可能会改变!所以我想要做那动态!我可以在此之前创建一个,并创建所需的所有实例,但它会显示一些硬编码! – baDa 2009-07-03 17:49:13

1

要检查NSNull你可以简单地比较反对的指针,因为它是一个单例:

if ([NSNull null] == [arrAllBlocks objectAtIndex:iLine]) { 
    [arrAllBlocks insertObject:[NSMutableArray array] atIndex:iLine]; 
} 
NSMutableArray *columnArray = [arrAllBlocks objectAtIndex:iLine]; 
[columnArray insertObject:newBlock atIndex:iColumn]; 

我也去掉了难看的转换。 Objective-C中很少需要铸造。它通常只会增加噪音,并可以隐藏真正的错误。由于您遇到崩溃,因此应该从该代码中移除强制转换,并听取编译器告诉您的信息。

告诉编译器忽略一段代码的警告并不会导致它的根本问题消失!

相关问题