有没有办法用 KVC 获取数组数组的所有第一个对象?

Is there a way to get all the first objects of an array of arrays with KVC?

假设我有一个数组,如:

NSArray *array = @[@[@1, @2], @[@3, @4], @[@5, @6]];

是否有 KVC 密钥路径可以给我@[@1, @3, @5]?

令我惊讶的是,虽然它依赖于一些未记录的行为。

NSArray 覆盖 -valueForKey: 的文档说它通过将 -valueForKey: 应用到具有提供的键和 returns 的每个元素来构建一个新数组。它确实暗示任何键都是特殊的。

然而,NSDictionary 的覆盖确实表示以 @ 开头的键被特殊对待。它不是查看字典的内容,而是查看字典本身的属性,以查找与删除前导 @ 的键相匹配的字典。因此,您可以使用 [someDict valueForKey:@"@count"] 来获取字典中对象的数量。

事实证明,NSArray 实际上遵守相同的约定。您可以在示例中使用 [array valueForKey:@"@firstObject"] 来获取 @[@[@1, @2]]。现在的问题是,如何将其应用于内部数组,而不是外部数组。

首先,如果您只调用 [array valueForKey:@"firstObject"] 而键上没有 @ 会怎样?外部数组对每个内部数组调用 [innerArray valueForKey:@"firstObject"]。每个内部数组依次尝试对其每个元素调用 [element valueForKey:@"firstObject"]。但是,它的元素是 NSNumber 个对象,这些对象不符合密钥 "firstObject" 的 KVC。这样就爆炸了。

但是,KVC 支持 collection operators-valueForKeyPath:(注意最后的 "Path")。一位运算符是 @unionOfObjects。这会将运算符右侧的路径部分应用于数组的元素,然后 returns 结果数组。这类似于 -valueForKey: 传播到内部数组的情况,只是您需要为内部数组指定不同的键。

因此,结合这些机制,您可以:[array valueForKeyPath:@"@unionOfObjects.@firstObject"] 得到 @[@1, @3, @5]。外部数组将 [innerArray valueForKeyPath:@"@firstObject"] 应用于每个内部数组。由于前导 @,它不会传播到内部数组的元素。它只是获取内部数组的 firstObject 。然后外部数组将它们组合成一个结果数组。

KVC 键路径仅在对象为 confirming Key Value coding compliance 时有效。表示 object , scaler 值应该在键名上有 setter 和 getter 。在您的结构中,索引路径没有键 getter 和 setter。所以我创建了自定义 getter 方法来满足内部对象索引路径的 NSKeyValueCoding。这将适用于内部数组的每个索引。

@interface NSArray (KVO)
- (id) unionOfObjectsForKeyPath:(NSString*)keyPath;
@end

@implementation NSArray (KVO)

- (id) unionOfObjectsForKeyPath:(NSString*)keyPath
{
     NSMutableArray * values = [NSMutableArray new];
     for (id obj in self) {
        if ([obj isKindOfClass:[NSArray class]]) {

          @try {
              NSUInteger index = [keyPath integerValue];
              id value = nil;
              if (index < [(NSArray *)obj count]) {
                  value = [obj objectAtIndex:index];
                  if(value && value!=[NSNull null] )
                  {
                     [values addObject:value];
                  }
              }
          }
          @catch (id) {}
       }
    }
    return [NSArray arrayWithArray:values];
  }
 @end

在 VC 中:

 self.myArray = @[@[@1, @2], @[@3, @4], @[@5, @6]];
 NSArray *testArray =[self.myArray unionOfObjectsForKeyPath:@"0"];
 NSLog(@"test array : %@", testArray);