4

我正在使用这种方法将方法分派给委托,不幸的是我发现大多数时候 NSMethodSignature 是 nil,这是由于选择器来自协议的事实。我想知道哪种方法是正确的:

  1. Aks 方法是否来自协议
  2. 获取协议方法的签名

[编辑]
根据 newacct 用户的观察,我的问题不正确,签名为零是正常的,但不是因为是协议,而是因为我要求方法签名针对错误的对象。Self在这种情况下,它没有实现我想要调度的方法,它是使用和实现它们的委托。

这是代码:

- (BOOL) dispatchToDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err {
 NSMethodSignature *methodSig = [[self class] instanceMethodSignatureForSelector:selector];
 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig]; 
[invocation setTarget:self.delegate]; 
BOOL result = NO; 
if([self.delegate respondsToSelector: selector]) {
        if(arg != NULL) {
            [invocation setArgument:&arg atIndex:2];      
            [invocation setArgument:&err atIndex:3];  
    }else {
        [invocation setArgument:&err atIndex:2];      

    }
    if ([NSThread isMainThread]) {
        [invocation invoke];        
    }
    else{
        [invocation performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:YES];
    }
    [invocation getReturnValue:&result];
}
else
    NSLog(@"Missed Method");
return result;
}


[已更新] 我修改了 Apple 邮件列表中的一个方法

- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector
{
    NSMethodSignature *theMethodSignature = [super methodSignatureForSelector:inSelector];
    if (theMethodSignature == NULL)
    {
        struct objc_method_description theDescription = protocol_getMethodDescription(@protocol(GameCenterManagerDelegate),inSelector, NO, YES);
        theMethodSignature = [NSMethodSignature signatureWithObjCTypes:theDescription.types];
    }
    return(theMethodSignature);
}

它可以工作,但我会遵循 bbum 的建议,代码变得非常复杂......喜欢很快就会中断。

4

1 回答 1

3

做就是了:

if ([delegate respondsToSelector:@selector(someMethod:thatDoesSomething:)]) {
    dispatch_async(dispatch_get_main_queue(), ^{
        [delegate someMethod:foo thatDoesSomething:bar];
    }
}

使用运行时变魔术的诱惑很强烈,但这只会导致代码过于复杂,难以理解,速度较慢,并且不能真正节省那么多代码行。它也更难重构。

这显然没有考虑返回值。不过,为此,您确实希望避免任何类型的阻塞调用。告诉主线程去做某事,然后让它在完成后安排一个块在适当的队列上执行。这将降低死锁的风险,并使您的整体应用程序设计更加简单。

请注意,当从主线程调用时,上面的代码将导致块在下一次通过主事件循环时执行。无论如何,这可能是您想要的,因为它将与并发案例的行为一致。

于 2013-06-09T17:57:23.157 回答