【问题标题】:NSMutableArray check if object already existsNSMutableArray 检查对象是否已经存在
【发布时间】:2011-09-11 14:16:49
【问题描述】:

我不知道该怎么做。我有一个 NSMutableArray (addList),其中包含要添加到我的数据源 NSMutableArray 的所有项目。

我现在想检查要从 addList 数组添加的对象是否已存在于数据源数组中。如果不存在则添加该项目,如果存在则忽略。

这两个对象都有一个我想比较的名为 iName 的字符串变量。

这是我的代码 sn-p

-(void)doneClicked{
    for (Item *item in addList){
        /*
        Here i want to loop through the datasource array 
        */
        for(Item *existingItem in appDelegate.list){
            if([existingItem.iName isEqualToString:item.iName]){
                // Do not add
            }
            else{
                [appDelegate insertItem:item];
            } 
        }
}

但我发现要添加的项目即使存在。

我做错了什么?

【问题讨论】:

  • 逻辑错误,看我的回答

标签: iphone objective-c ios nsmutablearray


【解决方案1】:

你比较addList的第一个对象和appDelegate.list的第一个对象,如果不相等,你就插入addList的对象。逻辑不对,应该把addList的一个对象和appDelegate.list的每个对象进行比较。

【讨论】:

    【解决方案2】:

    在 NSArray 中有一个非常有用的方法,即 containsObject

    NSArray *array;
    array = [NSArray arrayWithObjects: @"Nicola", @"Margherita",                                       @"Luciano", @"Silvia", nil];
    if ([array containsObject: @"Nicola"]) // YES
    {
        // Do something
    }
    

    【讨论】:

      【解决方案3】:

      看看 NSSet。您可以添加对象,并且仅当对象是唯一的时才会添加该对象。您可以从 NSArray 创建 NSSet,反之亦然。

      【讨论】:

        【解决方案4】:

        我找到了一个解决方案,可能不是最有效的,但至少有效

        NSMutableArray *add=[[NSMutableArray alloc]init];
        
        for (Item *item in addList){
                if ([appDelegate.list containsObject:item])
                    {}
                else
                    [add addObject:item];
        }
        

        然后我遍历添加数组并插入项目。

        【讨论】:

          【解决方案5】:

          转换小写并修剪空白,然后检查..

          [string lowercaseString];  
          

          NSString *trim = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
          

          【讨论】:

            【解决方案6】:

            使用NSPredicate

            NSArray *list = [[appDelegate.list copy] autorelease];
            
            for (Item *item in addList) {
            
                NSPredicate *predicate = [NSPredicate predicateWithFormat:@"iName MATCHES %@", item.iName];
                NSArray *filteredArray = [list filteredArrayUsingPredicate:predicate];
                if ([filteredArray count] > 0) [appDelegate insertItem:item];
            }
            

            【讨论】:

            • +1 不错的答案。还避免了如果问题中使用的方法实际有效时会发生的变异集合异常。
            • 我尝试了上面编辑的解决方案。首先,程序崩溃而没有显示任何错误。其次,Item即使存在于数据源列表中也会被添加
            • @simon:感谢您的回答。但是程序仍然崩溃:(我现在只是在敲我的头:(
            • @Narayanan,你能说出程序在哪一行崩溃吗?
            • @simon:它在我们创建谓词的地方崩溃。 [NSComparisonPredicate isEqualToString:]: 无法识别的选择器发送到实例 0x7154070
            【解决方案7】:

            NR4TR 说的对,但我认为一个 break 声明就足够了

            
            if([existingItem.iName isEqualToString:item.iName]){
                            // Do not add
            break;
                        }
            

            【讨论】:

              【解决方案8】:

              你试过indexOfObject:吗?

              -(void)doneClicked{
                  for (Item *item in addList){
                      if([appDelegate.list indexOfObject:item] == NSNotFound){
                          [appDelegate insertItem:item];
                      }
              }
              

              更新:你有一个逻辑错误,而不是代码错误。假设第一个数组是 ['a', 'b', 'c'],第二个是 ['a', 'x', 'y', 'z']。当您使用 'a' 遍历第二个数组时,它不会在第一次迭代中将 'a' 添加到第二个数组(将 'a' 与 'a' 进行比较),但会在第二次中添加(比较 'a' 与 'x ')。这就是为什么您应该在您的“项目”对象中实现isEqual: 方法(见下文)并使用上面的代码。

              - (BOOL)isEqual:(id)anObject {
                  if ([anObject isKindOfClass:[Item class]])
                      return ([self.iName isEqualToString:((Item *)anObject).iName]);
                  else
                      return NO;
              }
              

              【讨论】:

              • @NR4TR:我想单独比较名称。不是整个对象
              • 是的,我现在明白了。但是当我使用您更新的代码时,我收到以下错误 [Item isEqualToString:]: unrecognized selector sent to instance 0x712ee70
              • 检查 isEqual: 方法在 Item 类中的实现
              • 抱歉,我好像没跟上。 Item 是我自己创建的一个类,我根本没有 isEqual 方法。你能帮我详细介绍一下吗?
              • 查看更新。只需将此 isEqual: 方法粘贴到您的 Item 实现中
              【解决方案9】:

              您可以在对象上覆盖 isEqualshash,以便它根据 iName 属性的比较返回 YES / NO。

              一旦你有了,你就可以使用......

              - (void)removeObjectsInArray:(NSArray *)otherArray
              

              在添加所有剩余对象之前清理列表。

              【讨论】:

              • 首先,我想单独比较名称而不是整个对象。
              • 考虑阅读有关isEquals 方法的文档,它会有所帮助
              • 是的,覆盖 isEquals 的想法是您可以定义您认为“相等”的内容。通常,运行时会查看两个对象,如果它们不是同一个实例,则返回 false。通过覆盖 isEquals 方法,您可以说“实际上我不在乎 OBJECTS 是否不同,在我看来,如果名称匹配,这两个项目是相同的。”
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-09-26
              • 1970-01-01
              • 2017-02-24
              • 1970-01-01
              • 2010-12-21
              相关资源
              最近更新 更多