【问题标题】:Detect if one position in Array is already initiated检测 Array 中的一个位置是否已经启动
【发布时间】:2009-07-03 17:24:39
【问题描述】:

我需要检查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之类的方法了!

【问题讨论】:

    标签: iphone objective-c cocoa-touch


    【解决方案1】:

    你有几个选择:

    选项 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 消息,但这只会将其保留计数再次减少到一个。那时,它会一直停留在 RAM 中,直到您的程序退出。

    这里最好使用[NSMutableArray arrayWithCapacity:0] 代替(正如我在示例中所做的那样)。这将返回一个新的NSMutableArray,与您的代码一样,但该实例已经是autoreleased。这样,arrAllBlocks 可以取得新对象的所有权,并且您可以确定它会在适当的时候被释放。

    【讨论】:

      【解决方案2】:

      你不能。 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];
      

      【讨论】:

      • 嗯,好的!但是我尝试了你所说的,但还没有工作=/我需要这个,因为 arrAllBlocks 中的对象数量可能会改变!所以我想做那个动态的!我可以在此之前创建一个 for,并创建我需要的所有实例,但它看起来有点硬编码!
      • @Dave DeLong:您对 NSNull 对象的使用是正确的,但是 baDa 必须用它们预先填充他的数组才能使其工作。如果他要这样做,他还不如用空的 NSMutableArrays 预先填充数组。我发布了一个包含更多详细信息的答案。
      • @eJames:好点子,好答案(我投了赞成票)。 NSNull 适用于他想要维护索引但仍然“消除”数组中某些位置的情况。 =)
      【解决方案3】:

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

      告诉编译器忽略一段代码的警告并不会解决它的潜在问题!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-15
        • 2013-02-10
        • 2019-01-21
        • 2010-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多