【问题标题】:Remove object from NSMutableArray?从 NSMutableArray 中删除对象?
【发布时间】:2013-04-15 13:05:48
【问题描述】:

我在ViewDidLoad 方法中有一个包含以下元素的数组

inputArray = [NSMutableArray arrayWithObjects:@"car", @"bus", @"helicopter", @"cruiz", @"bike", @"jeep", nil];

我有另一个UITextField 用于搜索元素。所以一旦我在UITextField 中输入一些内容,我想检查该字符串是否存在于“inputArray”中。如果它与 inputArray 中的元素不匹配,那么从 inputArray 中删除相应的元素。

 for (NSString* item in inputArray)
   {
        if ([item rangeOfString:s].location == NSNotFound) 
        {
            [inputArray removeObjectIdenticalTo:item];//--> Shows Exception
            NSLog(@"Contains :%@",containsAnother);
        }

  }

但此代码显示异常,与“removeobject:”相关的内容

例外:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSCFConstantString rangeOfString:options:range:locale:]: nil argument'
*** First throw call stack:
`

【问题讨论】:

  • 您遇到了什么异常?它必须是可变的。但根据你的问题,它不是。
  • 由于未捕获的异常 'NSInvalidArgumentException' 导致应用程序终止,原因:'*** -[__NSCFConstantString rangeOfString:options:range:locale:]: nil argument' *** 第一次抛出调用堆栈:跨度>
  • @Naveen 如果这是你的例外,你应该看看你的论点(可能是s),看看哪个是nil

标签: ios objective-c search nsstring nsmutablearray


【解决方案1】:

您可以使用以下代码

for (int i=0;i<[inputArray count]; i++) {
        NSString *item = [inputArray objectAtIndex:i];
        if ([item rangeOfString:s].location == NSNotFound) {
            [inputArray removeObject:item];
            i--;
        }
    }

【讨论】:

  • 这是有道理的。或者,您可以以相反的顺序迭代索引 i,,这样可以节省您在删除项目时需要调整索引的工作。但我喜欢这个。
  • 另外你需要提一下为什么这种方式适应,而不是快速枚举。
  • 如果你对一个对象执行快速枚举,你不能从中删除对象。如果您尝试从正在快速枚举的 NSMutableArray 中删除对象,它将引发异常。这就是我使用传统 for 循环的原因。
【解决方案2】:

在快速枚举中,您可以修改集合。

枚举器对象变为常量且不可变。

如果你想对数组进行更新

你应该喜欢这个:

NSMutableArray *inputArray = [NSMutableArray arrayWithObjects:@"car", @"bus", @"helicopter", @"cruiz", @"bike", @"jeep", nil];
NSString *s=@"bus";

for (int i=inputArray.count-1; i>-1; i--) {
    NSString *item = [inputArray objectAtIndex:i];
    if ([item rangeOfString:s].location == NSNotFound) {
        [inputArray removeObject:item];
    }
}

编辑:

上面的工作与此类似:

NSArray *array=[inputArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF CONTAINS[c] %@",s]]; 

【讨论】:

  • item 来自 inputArray 而 s 也来自 inputArray??那么我在哪里添加我的搜索文本?
  • 您可能应该打破if 中的循环,从而保证您只删除第一次出现或将索引计数器减一,因为您已删除一个项目并因此“删除”数组的其余部分加一。由于这在 for 循环中可能看起来很奇怪,因此您可以改用 while 循环。
  • 我只是将您的代码转换为常规的 for 循环。休息你比我更了解:)
  • @AnoopVaidya +1 指出filteredArrayUsingPredicate。如果使用NSMutableArray,也可以直接filterUsingPredicate
  • @Rob 我喜欢直接使用filterUsingPredicate: 的想法 - 它可以在一行易于理解的代码中完成 OP 的要求。
【解决方案3】:

必须是NSMutableArrayNSArray 一旦创建就不能修改(除非重新开始)。

改变这个:

inputArray = [NSArray arrayWithObjects:@"car", @"bus", @"helicopter", @"cruiz", @"bike", @"jeep", nil];

到这里:

inputArray = [NSMutableArray arrayWithObjects:@"car", @"bus", @"helicopter", @"cruiz", @"bike", @"jeep", nil];

并将属性也更改为 NSMutableArray:

@property(nonatomic, strong) NSMutableArray *inputArray;

【讨论】:

  • 使用你的编码后得到'NSInvalidArgumentException',原因:'*** -[__NSCFConstantString rangeOfString:options:range:locale:]: nil argument'
【解决方案4】:

您问题中的s 可能为零。所以你得到了例外。请检查一下。

【讨论】:

    【解决方案5】:

    使用以下代码。 (此代码用于根据UITextField 的输入字符串/文本过滤数组

    ViewDidLoad 方法中取两个NSMutableArray将一个数组添加到另一个数组

    self.listOfTemArray = [[NSMutableArray alloc] init]; // array no - 1
    self.ItemOfMainArray = [[NSMutableArray alloc] initWithObjects:@"YorArrayList", nil]; // array no - 2 
    
    [self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray]; // add 2array to 1 array
    

    并编写如下 UISearchBar 的委托方法

    - (BOOL) textFieldDidChange:(UITextField *)textField
     {
            NSString *name = @"";
            NSString *firstLetter = @"";
    
        if (self.listOfTemArray.count > 0)
             [self.listOfTemArray removeAllObjects];
    
            if ([searchText length] > 0)
            {
                    for (int i = 0; i < [self.ItemOfMainArray count] ; i = i+1)
                    {
                            name = [self.ItemOfMainArray objectAtIndex:i];
    
                            if (name.length >= searchText.length)
                            {
                                    firstLetter = [name substringWithRange:NSMakeRange(0, [searchText length])];
                                    //NSLog(@"%@",firstLetter);
    
                                    if( [firstLetter caseInsensitiveCompare:searchText] == NSOrderedSame )
                                    {
                                        // strings are equal except for possibly case
                                        [self.listOfTemArray addObject: [self.ItemOfMainArray objectAtIndex:i]];
                                        NSLog(@"=========> %@",self.listOfTemArray);
                                    }
                             }
                     }
             }
             else
             {
                 [self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray ];
             }
    
            [self.tblView reloadData];
    }
    

    }

    输出显示在您的Console.

    【讨论】:

      【解决方案6】:

      正如其他人所说,您不能在枚举数组时对其进行变异。做你想做的事情并保持快速枚举的便利的最简单方法是复制数组。

      for (NSString* item in [inputArray copy]) {
         ...
      }
      

      【讨论】:

      • 请注意,一旦您删除了inputArray 中的一个元素,inputArray[inputArray copy] 的索引就不再匹配了。
      【解决方案7】:

      这是我喜欢使用的干净解决方案。您定义一个 NSArray 类别来扩展它并创建一个 ma​​p 方法。此方法根据您在块中返回的内容创建一个新的 NSArray:

      @interface NSArray (BlockExtensions)
      /*! 
       Invokes block once for each element of self, returning a new array containing the
       values returned by the block.
       */
      - (NSArray *)map:(id (^)(id obj))block;
      
      @end
      
      @implementation NSArray (BlockExtensions)
      
      - (NSArray *)map:(id (^)(id obj))block
      {
          return [self mapWithOptions:0 usingBlock:^id(id obj, NSUInteger idx) {
              return block(obj);
          }];
      } 
      
      - (NSArray *)mapWithOptions:(NSEnumerationOptions)options usingBlock:(id (^)(id obj, NSUInteger idx))block
      {
          NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self count]];
          [self enumerateObjectsWithOptions:options usingBlock:^(id obj, NSUInteger idx, BOOL *stop)     {
      
              id newobj = block? block(obj, idx) : obj;
              if (newobj)
                  [array addObject:newobj];
          }];
          return array;
      }
          @end
      

      将为原始数组中的每个项目调用一次该块,将此对象作为参数传递:

      NSArray *newArray = [inputArray map:^id(NSString *item) {
          if ([item rangeOfString:s].location == NSNotFound) {
              return item;
          }
          return nil;
      }];
      

      newArray 将包含您过滤掉的项目!

      【讨论】:

      • 那么mapWithOptions从何而来?
      • 是的,对不起。你去吧。 :)
      【解决方案8】:

      +1 到 Anoop 指出您可以使用 filteredArrayUsingPredicate。因此,如果您想根据inputArray 中的匹配项创建一个新数组,您还可以使用类似:

      NSArray *matchingArray = [inputArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF contains[c] %@", s]];
      

      或者,假设inputArrayNSMutableArray,您可以简单地用这一行过滤数组:

      [inputArray filterUsingPredicate:[NSPredicate predicateWithFormat:@"SELF contains[c] %@", s]];
      

      或者,如果你喜欢积木:

      [inputArray filterUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
          return ([evaluatedObject rangeOfString:s].location != NSNotFound);
      }]];
      

      【讨论】:

        猜你喜欢
        • 2011-02-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多