Objective-C check block type?

This is different from other "I can check the block type" messages on SO, as far as I can tell.

I want to know if, given the block object of an unknown signature, I can find out what arguments it takes before the call?

I have a situation where I have several callbacks associated with objects in a dictionary. I want some of these callbacks to expect a different set of arguments. The example here is extremely simplified, but I think it makes sense.

How can I find out if this block was previously a type before?

//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]); } } 
+7
source share
4 answers

Honestly, if callbacks are of different types, they must be under different keys. Why not use the @"callbackWithOneParam" and @"callbackWithTwoParams" keys? For me, this is higher than the common โ€œcallbackโ€ key plus the separate โ€œtypeโ€ key to tell you how to interpret the callback.

But actually it requires the use of custom class objects instead of dictionaries. You crossed the border where shared objects are no longer convenient and begin to cause more problems than they solve.

+2
source

When you call a block, you MUST know the type of its arguments. In your case, if the โ€œnameโ€ is not enough to determine what arguments should be, I would add another key โ€œtypeโ€ that will tell me. Here is an example:

 // 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"]; } } } 

Note that you need the block to be bound to the correct type, otherwise you are likely to run into your program. This is because the block depends on the compiler to push the arguments onto the stack in the correct order and allow any return type.

0
source

Personally, I use the ingenious CTBlockDescription ...

CTBlockDescription allows you to check blocks, including arguments and compile-time functions at runtime.

 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} 

Great ...

0
source

just check if the name is "Foo" or "Bar"? probably there will be as much effort as checking the parameters of the functions that I have a feeling is impossible without having it in some form of class and going

 if ([myObject class] == [MyClass class]) 
-one
source

All Articles