Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/38.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone Grand Central Dispatch(GCD)与performSelector-需要更好的解释吗_Iphone_Objective C_Multithreading_Ios_Grand Central Dispatch - Fatal编程技术网

Iphone Grand Central Dispatch(GCD)与performSelector-需要更好的解释吗

Iphone Grand Central Dispatch(GCD)与performSelector-需要更好的解释吗,iphone,objective-c,multithreading,ios,grand-central-dispatch,Iphone,Objective C,Multithreading,Ios,Grand Central Dispatch,我在应用程序中同时使用了GCD和performSelectorOnMainThread:waitUntilDone,并且倾向于认为它们是可互换的——也就是说,performSelectorOnMainThread:waitUntilDone是GCD C语法的Obj-C包装器。我一直认为这两个命令是等效的: dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; }); [self performSelectorOnMainTh

我在应用程序中同时使用了GCD和performSelectorOnMainThread:waitUntilDone,并且倾向于认为它们是可互换的——也就是说,performSelectorOnMainThread:waitUntilDone是GCD C语法的Obj-C包装器。我一直认为这两个命令是等效的:

dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; });


[self performSelectorOnMainThread:@selector(doit:) withObject:YES waitUntilDone:YES];

我错了吗?也就是说,performSelector*命令与GCD命令之间是否存在差异?我已经阅读了很多关于它们的文档,但还没有看到一个明确的答案。

performSelectorOnMainThread:不使用GCD向主线程上的对象发送消息

下面是该方法的实现方式:

- (void) performSelectorOnMainThread:(SEL) selector withObject:(id) obj waitUntilDone:(BOOL) wait {
  [[NSRunLoop mainRunLoop] performSelector:selector target:self withObject:obj order:1 modes: NSRunLoopCommonModes];
}
在执行选择器:目标:withObject:order:modes:上,文档说明:

此方法设置计时器,以便在下一次运行循环迭代开始时对当前线程的运行循环执行aSelector消息。定时器配置为在modes参数指定的模式下运行。当计时器触发时,线程尝试从运行循环中退出消息队列并执行选择器。如果运行循环正在运行且处于指定模式之一,则会成功;否则,计时器将等待运行循环处于这些模式之一


正如雅各布所指出的,虽然它们看起来是一样的,但它们是不同的东西。事实上,如果您已经在主线程上运行,那么它们处理向主线程发送操作的方式有很大的不同

我最近遇到了这个问题,我有一个常用的方法,有时候是从主线程上的某个东西运行,有时候不是。为了保护某些UI更新,我一直在使用
-performSelectorOnMainThread:
来保护它们,没有任何问题

当我切换到在主队列上使用
dispatch\u sync
时,只要在主队列上运行此方法,应用程序就会死锁。阅读上的文档,我们看到:

调用此函数并确定目标 当前队列导致死锁

我们去哪里看

等等

一个布尔值,指定 当前线程阻塞,直到 在上执行指定的选择器 主线程上的接收器。具体说明 是以阻止此线程;否则,, 指定NO以返回此方法 马上

如果当前线程也是主线程 线程,并为此指定“是” 参数,则消息已传递 并立即处理

我仍然更喜欢GCD的优雅、它提供的更好的编译时检查,以及它在参数等方面更大的灵活性,因此我制作了这个小助手函数来防止死锁:

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}
更新:针对Dave Dribin指出的问题,我已改为在上述代码中使用
[NSThread isMainThread]

然后我使用

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});

要执行我需要在主线程上保护的操作,不必担心原始方法是在哪个线程上执行的。

GCD的方式应该更高效、更易于处理,并且仅在iOS4以后的版本中可用,而在旧版和新版的iOS中支持PerformSelect。

withObject:YES将不起作用,至少应该给您一个警告。这可能是GDC的一个优点,在GDC中,您可以向接收者发送任意参数。好的,我需要将其包装在一个NSNumber中。但是,忽略这一部分,还有什么不同吗?不过,这一点很好。@Joe-
dispatch\u sync()
到主线程仍然可能导致应用程序死锁,如果主线程上的某些内容在等待后台线程的值时被阻止(通过
dispatch\u sync()
或其他方式)。这不太可能,但仍有可能。这是两个线程等待另一个线程执行某些操作的标准线程问题,因此什么也做不到。迂腐的溢出:您可以使用
dispatch\u block\u t
作为参数类型,而不是丑陋的
void(^block)(void)
@Adam-自从我写这篇文章以来,该部分似乎已经更新。它曾经告诉您,身份检查不一定适用于
调度\u get\u current\u queue()
。这已添加到警告部分:
如果队列不是调度\u get\u current\u queue()返回的队列,则代码假设队列上的同步执行不会死锁,这同样是不安全的.
@BradLarson使用
dispatch\u async(dispatch\u get\u main\u queue(),block)怎么样?
?有什么问题吗?