Objective-C类型检查块?
这是不同于其他“我可以检查一个块的类型”的帖子,所以,据我所知无论如何 我想知道,给定一个签名未知的块对象,我是否可以在调用之前了解它接受哪些参数 在这种情况下,我有许多回调与字典中的对象关联。我希望这些回调中的一些回调预期一组不同的参数。这里的例子非常简单,但我认为它能说明问题 如何确定块是否为我以前键入的类型Objective-C类型检查块?,objective-c,ios,objective-c-blocks,Objective C,Ios,Objective C Blocks,这是不同于其他“我可以检查一个块的类型”的帖子,所以,据我所知无论如何 我想知道,给定一个签名未知的块对象,我是否可以在调用之前了解它接受哪些参数 在这种情况下,我有许多回调与字典中的对象关联。我希望这些回调中的一些回调预期一组不同的参数。这里的例子非常简单,但我认为它能说明问题 如何确定块是否为我以前键入的类型 //MyClass.m // I start by declare two block types typedef void (^callbackWithOneParam)(NSSt
//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]);
}
}
只要检查一下名字是“Foo”还是“Bar”?这可能和检查函数参数一样费劲,我觉得如果不在某种形式的类中使用它,就不可能做到这一点
if ([myObject class] == [MyClass class])
调用块时,必须知道其参数的类型。在您的情况下,如果“name”不足以确定参数应该是什么,我将添加另一个键“type”,它将告诉我。以下是一个例子:
// 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"];
}
}
}
请注意,必须将块强制转换为正确的类型,否则可能会导致程序崩溃。这是因为块依赖于编译器将参数以正确的顺序放入堆栈,并允许任何返回类型。坦白地说,如果回调具有不同的类型,那么它们应该位于不同的键下。为什么不使用键
@“callbackWithOneParam”
和@“callbackWithTwoParams”
?对我来说,这比使用一个通用的“回调”键加上一个单独的“type”键来告诉您如何解释回调要好
但这真正需要的是使用自定义类的对象而不是字典。你已经越过了通用对象不再方便的界限,开始造成比它们解决的问题更多的问题。就个人而言,我使用了巧妙的 CTBlockDescription允许您在运行时检查包含参数和编译时功能的块
参数数量=3
框架尺寸=12
特殊结构是否返回?不
返回值:-------------------------------
类型编码(c)‘c’
标志{isSigned}
修饰语{}
帧{offset=0,offset adjust=0,size=4,size adjust=-3}
内存{offset=0,size=1}
参数0:------------------------------
类型编码(@)@?“
标志{isObject,isBlock}
修饰语{}
帧{offset=0,offset adjust=0,size=4,size adjust=0}
内存{offset=0,size=4}
论据1:---------------------
类型编码(c)‘c’
标志{isSigned}
修饰语{}
帧{offset=4,offset adjust=0,size=4,size adjust=-3}
内存{offset=0,size=1}
论据2:-------------------------
类型编码(@)@'
标志{isObject}
修饰语{}
帧{offset=8,offset adjust=0,size=4,size adjust=0}
内存{offset=0,size=4}
漂亮…我想你不能。在您的情况下,您可以只保留额外的参数NSObject,如果不使用它,则将其置为nil。在本例中,最好对字典中的所有块使用一致的签名。然后,每个块中的代码可以独立决定使用或忽略哪些参数。在调用块之前,还必须将返回值从
-objectForKey:
强制转换为块签名。在将每个块添加到字典之前,您还必须将其复制到堆中。Darren您能否详细介绍一下您的最后两个语句,谢谢!首先,您的字典语法无效。您可能是指类似于@{@“Foo”:^(…){…},@“Bar”:^(…){…}
。第二,在将块放入字典之类的泛型集合之前,需要先复制它,否则会发生不好的事情。创建NSOperation的子类。为此,您确实应该使用isKindOfClass:
或isMemberClass:
来+1推荐自定义类而不是字典。
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}