使用Grand Central Dispatch,如何检查是否已经运行了一个块?

时间:2011-07-14 14:04:37

标签: iphone objective-c ios grand-central-dispatch

我正在使用GCD从互联网上进行一些后台加载。除了有点瑕疵之外,这很有效。在我的应用程序中,我有3个选项卡,当单击任何选项卡时,GCD开始为相应的选项卡执行后台加载。如果用户决定从第一个选项卡转到第二个选项卡(当GCD开始下载第一个选项卡的数据时),然后再次返回第一个选项卡。 GCD将启动另一个后台线程(即使第一个后台线程尚未完成下载数据)。

那么有没有办法检查后台线程当前是否正在运行?因此,如果用户选择非常快速地来回切换标签(由于某种原因),它就不会启动多个后台线程。

2 个答案:

答案 0 :(得分:10)

如果要防止同一类型的两个块同时运行,可以使用调度信号量。将信号量设置为1,您可以在关闭块之前检查信号量,并在某些事情仍在运行时保释。在块结束时,您发信号通知信号量以允许提交其他块。

我在我的一个应用程序中执行此操作,以防止一次将多个OpenGL ES帧渲染块添加到队列中(如果帧花费的时间超过1/60秒,则阻止队列中的块累积渲染)。我在回答here中使用以下代码描述了一些内容:

if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0)
{
    return;
}

dispatch_async(openGLESContextQueue, ^{

    [EAGLContext setCurrentContext:context];

    // Render here

    dispatch_semaphore_signal(frameRenderingSemaphore);
});

其中frameRenderingSemaphore之前创建如下:

frameRenderingSemaphore = dispatch_semaphore_create(1);

如果为每个选项卡的下载操作创建类似的信号量,则可以检查以确保一次没有为该选项卡排队多个下载。

答案 1 :(得分:0)

你需要的是一个简单的布尔标志,以避免在任务完成之前再次启动任务(根本不涉及GDC)。像(伪代码,未测试,免责声明等):

- (void)something_you_run_in_your_view_did_appear
{
    synchronize(self) {
        if (self.doing_task)
            return;
        self.doing_task = YES;
    }
    start_your_task_here
}

- (void)something_you_run_when_the_task_finishes
{
    synchronize(self) {
        self.doing_task = NO;
    }
}

这个伪代码适用于异步NSURLConnection之类的东西。我还没有探索过GDC,其他人需要将它改编为GDC(你自己?)。

请注意,在此示例中,我使用的是属性而不是简单的变量访问。这允许您在setter中实现更好的东西,比如激活活动指示器,禁用用户界面输入等。当变量的状态在父变量中发生变化时,它也适用于执行他们的事物的子类类。