3

ここでの答えを使用すると、このメソッドは obj-c での ruby​​ のマップに似たものを実現します。

- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block {
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]];
    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        [result addObject:block(obj, idx)];
    }];
    return result;
}

私の質問は、ブロックの適用中に何か問題が発生した場合、オブジェクトをスキップするにはどうすればよいですか? 通常、列挙子で何かをスキップするには、returnコマンドを使用するだけですが、ブロックが何かを返すことが期待されているため、上記のメソッドではオプションではありません。

この例ではreturn、スキップするために使用しますが、エラーが発生します。

NSArray *mappedArray = [objArray mapObjectsUsingBlock:^(id obj, NSUInteger i) {
    // i don't want this obj to be included in final array
    // so I try to skip it
    return;   // ERROR:incompatible block pointer types sending 
              // 'void(^)(__strong id, NSUInteger)' to parameter of type 
              // 'id(^)(__strong id, NSUInteger)'


    // else do some processing
    return soupedUpObj;
}];

それを回避する私の現在の方法は、単純に null オブジェクトを返し、最終的な配列からそれらを削除することです。しかし、それよりも良い方法があるに違いないと確信しています。

4

3 に答える 3

5

実装が上に示したものと似ている場合は、ブロックの結果を中間値に適用し、それを結果の配列に追加する前にチェックするのが理にかなっています。このようなもの:

- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block {
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]];
    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        id blockResult = block( obj, idx );
        if( result != nil ){
          [result addObject:blockResult];
        }
    }];
    return result;
}
于 2013-08-21T15:44:18.287 に答える
1

1 つの簡単な解決策: NSArray ではなく NSPointerArray を使用する独自のバリアントを作成します。NSPointerArray は nil を保持できます。その後、順序を保持することができ、nil を使用してエラーを示すことができます (NSNull がエラーを示すために使用できない有効な値であると仮定します)。NSPointerArray を使用すると、ブロックは単に nil を返します。

于 2013-08-21T16:06:00.133 に答える
0

これは単に、フレームワークまたはライブラリmapObjectsUsingBlock:が由来する制限です (標準の Apple API ではありません)。

nilただし、配列マップ機能の実装は難しくないため、ブロック引数からの戻り値を処理する独自のバージョンを簡単に作成できます。

于 2013-08-21T14:47:28.347 に答える