This is different from other "can I check the type of a block" posts on SO, as far as I can tell anyway.
I want to know if, given a block object of unknown signature, I can learn what arguments it accepts prior to invoking?
I have a situation where I have a number of callbacks associated with objects in a dictionary. I want some of those callbacks to expect a different set of arguments. The example here is extremely simplified, but I think it gets the point across.
How can I find out if a block is of a type I previously typedef'd?
//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]);
}
}
__block is a storage qualifier that can be used in two ways: Marks that a variable lives in a storage that is shared between the lexical scope of the original variable and any blocks declared within that scope. And clang will generate a struct to represent this variable, and use this struct by reference(not by value).
The goal of the @property directive is to configure how an object can be exposed. If you intend to use a variable inside the class and do not need to expose it to outside classes, then you do not need to define a property for it. Properties are basically the accessor methods.
id is the generic object pointer, an Objective-C type representing "any object". An instance of any Objective-C class can be stored in an id variable.
For many of us, it's best practice to always use weak combined with self inside closures to avoid retain cycles. However, this is only needed if self also retains the closure. By adding weak by default you probably end up working with optionals in a lot of cases while it's actually not needed.
Frankly, if the callbacks have different types, they should be under different keys. Why not use the keys @"callbackWithOneParam"
and @"callbackWithTwoParams"
? To me, that's superior to having a generic "callback" key plus a separate "type" key to tell you how to interpret the callback.
But what this really calls for is to use objects of custom classes instead of dictionaries. You've crossed the boundary where generic objects stop being convenient and start to cause more problems than they solve.
Personally, I use the ingenious CTBlockDescription...
CTBlockDescription lets you inspect blocks including arguments and compile time features 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}
Gorgeous...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With