1

完全に形成されたブロック (すべてのパラメーターが含まれるブロック) をメソッドに渡して、そのブロックをメソッドで実行することは可能ですか?

現時点では、この構造をプロジェクトで繰り返しています。

 if (//block exists)
        {
            if (self.returnOnMainThread)
            {
                dispatch_async(dispatch_get_main_queue(), ^
                               {
                                   //call block here
                               });
            }
            else
            {
                //call block here
            }
        }

ただし、理想的には、上記のコードの塊を次のようなメソッドに抽象化したいと思います。

- (void) reportSuccessWithBlock:(GenericBlockType)block{
        if (block)
        {
            if (self.returnOnMainThread)
            {
                dispatch_async(dispatch_get_main_queue(), ^
                               {
                                   block;
                               });
            }
            else
            {
                block;
            }
        }

}

編集:

ブロックのタイプは事前にわかりません。

したがって、呼び出しパスは次のようになります

- (void) someMethod:(void (^)(NSArray *array))success
{
//Some code here setting up the array to be passed back

   [self reportSuccessWithBlock:success(array)];

}

上記のコードにはいくつかの仮定があります (可能かどうかはわかりません)。

  1. メソッドはジェネリック ブロック タイプを受け入れることができます
  2. ブロックは、すべてのパラメーターが存在する状態で渡すことができますが、実際には実行しません。
4

2 に答える 2

2

コメントで述べたように 2 つの異なるブロックがある場合は、次のように 2 つをマージできます。objectただし、これは非常にハックであり、ブロックが呼び出されたときに のクラスを確認する必要があります。

- (void) reportSuccessWithBlock:(void (^) (id object, NSUInteger value)) block {

    if (!block)
        return;

    if (self.returnOnMainThread) {
        dispatch_async(dispatch_get_main_queue(), block((id)someObject, value)); // return 0 instead if there is no value
    }

    else {
        block((id) someObject, value)); // return 0 instead if there is no value
    }
}

したがって、ブロックが呼び出されたときに必要なことは、クラスをチェックして、返されたオブジェクトを処理することだけです。

- (void) someMethod {

    [self reportSuccessWithBlock:^(id object, NSUInteger value) {

        if ([object isKindOfClass:[NSArray class]]) {

            // returned an NSArray and `value` is 0 (unset)

        }

        else if ([object isKindOfClass:[NSDictionary class]]) {

            // returned an NSDictionary and the `value` is not 0 (unset)

        }

        else {

            // something has gone wrong somewhere!

        }

    }];

}
于 2013-02-21T15:31:12.500 に答える
1

OK、パラメーターを使用するアイデアはうまくいくと思うNSArrayので、ブロックに同じ署名を付けることができます。

typedef void ^(MYBLOCK)(NSArray *args);

メソッドを次のように実装します。

- (void)reportSuccessWithBlock:(GenericBlockType)block
                  andArguments:(NSArray *)args
{
    if (block != nil)
    {
       if (self.returnOnMainThread)
       {
            dispatch_async(dispatch_get_main_queue(), ^{
                block(args);
            });
       }
       else
       {
           block(args);
       }
    }
}

そして、正しいタイプの引数が正しい順序でブロックに与えられていることを確認するだけの場合です (些細なことのように聞こえますが、これを間違えるとあらゆる種類の攻撃が発生します)。

MYBLOCK block1 = ^(NSArray *args) {
    // I accept NSNumber, NSString, NSValue
    NSAssert(args.count == 3, @"Invalid argument count");
    NSNumber *arg1 = args[0];
    NSString *arg2 = args[1];
    NSValue *arg3 = args[2];

    // Do my thing
};

そしてそれを次のように呼び出します:

[someClass reportSuccessWithBlock:block1
                     andArguments:@[ @(1), @"Hello", @(cgpoint) ]];
于 2013-02-21T15:47:30.940 に答える