9

これは、とにかく私が知る限り、SOに関する他の「ブロックのタイプを確認できますか」という投稿とは異なります。

署名が不明なブロックオブジェクトが与えられた場合、呼び出す前にそれが受け入れる引数を知ることができるかどうかを知りたいですか?

辞書内のオブジェクトに関連付けられたコールバックがいくつかある状況があります。これらのコールバックのいくつかに、異なる引数のセットを期待させたいです。ここでの例は非常に単純化されていますが、それがポイントを理解していると思います。

ブロックが以前にtypedefしたタイプであるかどうかを確認するにはどうすればよいですか?

//MyClass.m

// I start by declare two block types
typedef void (^callbackWithOneParam)(NSString*);
typedef void (^callbackWithTwoParams)(NSString*, NSObject*);

........

// I create a dictionary mapping objects to callback blocks

self.dict = @{
  @"name": "Foo",
  @"callback": ^(NSString *aString) {
    // do stuff with string
  }
}, {
  @"name": "Bar",
  @"callback": ^(NSString *aString, NSObject *anObject) {
    // do stuff with string AND object
  }
} 

.....

// Later, this method is called.  
// It looks up the "name" parameter in our dictionary, 
// and invokes the associated callback accordingly.

-(void) invokeCallbackForName:(NSString*)name {
   // What is the type of the result of this expression?
   [self.dict objectForKey: name]

   // I want to say: (pseudocode)
   thecallback = [self.dict objectForKey: name];
   if (thecallback is of type "callbackWithOneParam") {
      thecallback(@"some param")
   }
   else if (thecallback is of type "callbackWithTwoParams") {
      thecallback(@"some param", [[NSObject alloc] init]);
   }
}
4

4 に答える 4

3

率直に言って、コールバックのタイプが異なる場合、それらは異なるキーの下にある必要があります。@"callbackWithOneParam"キーと を使用しないのはなぜ@"callbackWithTwoParams"ですか? 私にとっては、一般的な「コールバック」キーに加えて、コールバックの解釈方法を示す別の「タイプ」キーを使用するよりも優れています。

しかし、これが実際に要求しているのは、辞書の代わりにカスタム クラスのオブジェクトを使用することです。一般的なオブジェクトが便利ではなくなり、解決するよりも多くの問題を引き起こし始める境界を越えました。

于 2013-03-31T10:16:10.833 に答える
1

個人的には、独創的なCTBlockDescriptionを使用しています...

CTBlockDescription を使用すると、実行時に引数やコンパイル時の機能を含むブロックを検査できます。

BOOL(^bk)(BOOL,id) = ^BOOL(BOOL ani, id obj) { return YES; };

[CTBlockDescription.alloc initWithBlock:bk].blockSignature.description;

<NSMethodSignature: 0x253f080>
    number of arguments = 3
    frame size = 12
    is special struct return? NO
    return value: -------- -------- -------- --------
        type encoding (c) 'c'
        flags {isSigned}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 4, size adjust = -3}
        memory {offset = 0, size = 1}
    argument 0: -------- -------- -------- --------
        type encoding (@) '@?'
        flags {isObject, isBlock}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 4, size adjust = 0}
        memory {offset = 0, size = 4}
    argument 1: -------- -------- -------- --------
        type encoding (c) 'c'
        flags {isSigned}
        modifiers {}
        frame {offset = 4, offset adjust = 0, size = 4, size adjust = -3}
        memory {offset = 0, size = 1}
    argument 2: -------- -------- -------- --------
        type encoding (@) '@'
        flags {isObject}
        modifiers {}
        frame {offset = 8, offset adjust = 0, size = 4, size adjust = 0}
        memory {offset = 0, size = 4}

素敵...

于 2014-01-19T05:52:42.697 に答える
0

ブロックを呼び出すときは、その引数の型を知っている必要があります。あなたの場合、「名前」が引数の内容を決定するのに十分でない場合、別のキー「タイプ」を追加して教えてくれます。次に例を示します。

// Callback dictionary 

_callbacks = @{
    @{@"name":@"foo", @"type":@(1), @"callback":^(int i) { NSLog(@"%d", i); }},
    @{@"name":@"bar", @"type":@(2), @"callback":^(int i, int j) { NSLog(@"%d", i+j); }},
    @{@"name":@"zap", @"type":@(3), @"callback":^(int i, int j, int k) { NSLog(@"%d", i+j+k); }},
    @{@"name":@"cab", @"type":@(4), @"callback":^(NSString *s) { NSLog(@"%lu",s.length); }},
    @{@"name":@"fog", @"type":@(5), @"callback":^(void) { NSLog(@"I can't see"); }}
}


-(void) invokeCallbackForName:(NSString*)name withArguments:(NSArray*)args {

    NSDictionary *info = _callbacks[name];

    if (info != nil) {
        id block = info[@"callback"];
        int type = [info[@"type"] intValue];
        switch (type) {

            case 1:  {
                int arg1 = [args[0] intValue];
                ((void(^)(int)) block)(arg1);
                break;
            }
            case 2:  {
                int arg1 = [args[0] intValue];
                int arg2 = [args[1] intValue];
                ((void(^)(int,int)) block)(arg1,arg2);
                break;
            }
            case 3:  {
                int arg1 = [args[0] intValue];
                int arg2 = [args[1] intValue];
                int arg3 = [args[2] intValue];
                ((void(^)(int,int,int)) block)(arg1,arg2,arg3);
                break;
            }
            case 5:  {
                NSString *arg1 = [args[0] intValue];
                ((void(^)(NSString*)) block)(arg1);
                break;
            }
            default:
                [NSExceptien raise:NSInvalidArgumentException format:@"Unsupported callback type"];

        }
    }
}

ブロックを正しい型にキャストすることが不可欠であることに注意してください。そうしないと、プログラムがクラッシュする可能性があります。これは、ブロックがコンパイラに依存して、引数を正しい順序でスタックに配置し、任意の戻り値の型を許可するためです。

于 2013-03-31T09:09:15.070 に答える
-1

名前が「Foo」か「Bar」かを確認してください。おそらく、関数のパラメーターをチェックするのと同じくらいの労力になるでしょう。これは、何らかの形のクラスにそれを持たせて行かなければ不可能だと感じています

if ([myObject class] == [MyClass class])
于 2012-11-22T11:33:56.443 に答える