7

我遇到了这个_cmd技巧:

-(void)methodToBeRunOnMainThreadWithObj:(id)object {
    if (![NSThread isMainThread) {
        [self performSelectorOnMainThread:_cmd withObject:object]
    } else {
        // ... method body
    }
}

这是确保在主线程上执行方法的可靠方法吗?

4

2 回答 2

7

这可行,但有点反模式。如果调用该方法的线程不是主线程,我会做的是抛出一个错误。调用者有责任确保在正确的线程上调用方法,这些黑客行为只会鼓励丑陋的代码。此外,如果您依赖此方法,那么每次调用此方法时,您的消息调度开销都会增加一倍。

如果你真的无法改变调用者的行为,你可以尝试以下方法:

-(void)methodToBeRunOnMainThreadWithObj:(id)object {
    dispatch_sync(dispatch_get_main_queue(), ^{
        // code goes here
    });
}

这将导致调度块内的所有代码在主线程上执行,并且该方法在完成之前不会返回。如果您希望该方法立即返回,则可以dispatch_async改用。如果您使用dispatch_sync,您甚至可以在具有非 void 返回类型的方法上使用此技巧。

此代码还具有支持具有非对象类型(int等)参数的方法的额外好处。它还支持具有任意数量参数的方法,而performSelector:withObject:其兄弟方法仅支持有限数量的参数。另一种方法是设置NSInvocation对象,这很痛苦。

请注意,这需要您平台上的 Grand Central Dispatch (GCD)。

于 2012-11-02T06:20:49.013 回答
3

_cmd转发很好,只要指定的选择器_cmd与文档中指定的定义/签名匹配:“该方法不应具有重要的返回值,并且应采用 id 类型的单个参数,或者不带参数。” . 如果它不匹配,那么你应该假设未定义的行为。并且为了 110% 的安全并遵守抽象机器,返回类型应该是id(或某些 objc 类型),并且结果不应返回拥有的引用。

于 2012-11-02T06:25:47.497 回答