【问题标题】:Searching for an object index in NSArray using an inline block使用内联块在 NSArray 中搜索对象索引
【发布时间】:2012-06-11 12:22:43
【问题描述】:

我已经看到了一些使用 NSArray indexOfObjectPassingTest 的示例,但我无法让它们工作(它们不会返回有效的索引)。 所以现在我正在尝试使用内联块。我通过 typedef'ing 一个块,然后将它设置为一个属性,合成它,并在构造函数中初始化它来完成它。 然而,这种方式会使整点静音,因为我可以轻松地创建一个方法并使用它(更少的输入,更少的努力)。

我想要达到的目标是:

Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex: ^NSInteger (NSString *keyword){ 
    for (Observations *obs in self.myAppointment.OBSERVATIONS) {
        if ([obs.TIME isEqualToString:keyword] == YES) return (NSInteger)[self.myAppointment.OBSERVATIONS indexOfObject:obs];
    }
    return (NSInteger)-1;
}];

但是 Xcode 根本没有它。我尝试了不同的变体,但将其声明为内联似乎是一个问题,这很奇怪,因为正如我所说,对它进行类型定义、声明和综合是这样的:

Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex:findObs(keyword)];

findObs 又是一个定义的块,它做同样的事情。 这是语法问题,还是我错过了其他更重要的东西?

【问题讨论】:

    标签: objective-c nsarray objective-c-blocks css


    【解决方案1】:

    -objectAtIndex:NSUInteger 作为参数,但您传递给它的是一个块(由^ 表示)。您的第二个示例使用keyword 参数调用findObs(可能是您的块),将该调用的结果传递给-objectAtIndex:

    您可能希望将-objectAtIndex:-indexOfObjectPassingTest: 结合起来:

    NSString *keyword = /* whatever */;
    NSArray *array = self.myAppointment.OBSERVATIONS;
    NSUInteger idx = [array indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop){ 
        Observations *obs = (Observations*)obj;
        return [obs.TIME  isEqualToString:keyword];
    }];
    if (idx != NSNotFound)
        Observations *obs = [array objectAtIndex:idx];
    

    【讨论】:

    • 谢谢,效果很好。所以,我认为将内联块作为 NSInteger 参数传递(本质上期望块的返回值作为参数传递)是不可行的,除非它的类型已定义和合成?
    • 你也可以直接调用你的块:[... objectAtIndex:(^NSInteger (NSString *k){ ... })(keyword)];,但事情开始看起来有点混乱。
    • 这个例子将返回数组中最后一个通过测试的对象。要在找到第一个对象后立即停止迭代,您必须将 *stop 设置为 YES
    • 通常不需要通过 objectAtIndex 调用的第一次搜索来迭代数组两次...
    • @TristanLeblanc 该示例返回第一个对象---indexOfObjectPassingTest:*stop 设置为YES 时停止迭代谓词返回YES。此外,objectAtIndex: 是一个 O(1) 操作,不会遍历数组。
    【解决方案2】:

    这是一个返回字符串数组中字符串索引的示例。它可以适应任何类型的对象。

    NSString* myString = @"stringToFind";
    NSUInteger objectIndex = [myStringArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
            return (*stop = ([obj isEqualToString:myString]));
        }];
    

    准确回答原问题:

    NSString *keyword = @"myKeyword";
    NSUInteger index = [self.myAppointment.OBSERVATIONS indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) { 
        return (*stop = [(Observations*)obs.TIME  isEqualToString:keyword]);
    }];
    Observations *obs = (index!=NSNotFound) ? self.myAppointment.OBSERVATIONS[index] : NULL;
    

    但是将一个叫做 TIME 的东西与一个关键字进行比较是很奇怪的…… ;)

    【讨论】:

      【解决方案3】:

      不需要 typedef 或综合任何东西来使您的第二个示例工作 - 只需从方法返回块,如下所示:

      -(NSUInteger(^)(NSArray *, NSString *))findObs {
          return ^(NSArray *array, NSString *keyword) {
              for (NSUInteger i = 0; i < [array count]; i++) {
                  Observations *obs = [array objectAtIndex:i];
                  if ([obs.TIME isEqualToString:keyword]) {
                      return i;
                  }
              }
              return NSNotFound;
          };
      }
      
      Observations *obs = [self.myAppointment.OBSERVATIONS objectAtIndex:[self findObs](keyword)];
      

      这里有一些good reasons for defining blocks as method return values, rather than inline

      【讨论】:

      • 您需要复制要返回的块,除非您使用 ARC 为您完成此操作
      • 是的,@user102008,没错。这些天我通常假设 ARC,除非从某人的代码示例中清楚地表明他们没有使用 ARC。
      猜你喜欢
      • 2011-08-16
      • 2023-03-03
      • 1970-01-01
      • 2020-12-13
      • 1970-01-01
      • 1970-01-01
      • 2011-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多