我遇到了这个_cmd
技巧:
-(void)methodToBeRunOnMainThreadWithObj:(id)object {
if (![NSThread isMainThread) {
[self performSelectorOnMainThread:_cmd withObject:object]
} else {
// ... method body
}
}
这是确保在主线程上执行方法的可靠方法吗?
我遇到了这个_cmd
技巧:
-(void)methodToBeRunOnMainThreadWithObj:(id)object {
if (![NSThread isMainThread) {
[self performSelectorOnMainThread:_cmd withObject:object]
} else {
// ... method body
}
}
这是确保在主线程上执行方法的可靠方法吗?
这可行,但有点反模式。如果调用该方法的线程不是主线程,我会做的是抛出一个错误。调用者有责任确保在正确的线程上调用方法,这些黑客行为只会鼓励丑陋的代码。此外,如果您依赖此方法,那么每次调用此方法时,您的消息调度开销都会增加一倍。
如果你真的无法改变调用者的行为,你可以尝试以下方法:
-(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)。
_cmd
转发很好,只要指定的选择器_cmd
与文档中指定的定义/签名匹配:“该方法不应具有重要的返回值,并且应采用 id 类型的单个参数,或者不带参数。” . 如果它不匹配,那么你应该假设未定义的行为。并且为了 110% 的安全并遵守抽象机器,返回类型应该是id
(或某些 objc 类型),并且结果不应返回拥有的引用。