使用Grand Central Dispatch,如何检查是否有块正在运行?

我使用GCD从互联网做一些背景加载。 这个工程很好,除了一点缺陷。 在我的应用程序中,我有3个选项卡,当点击任何选项卡时,GCD开始为适当的选项卡执行后台加载。 如果用户决定从第一个标签页到第二个标签页(当GCD开始下载第一个标签页的数据时),然后再次返回到第一个标签页。 GCD将启动另一个后台线程(即使第一个后台线程尚未完成下载数据)。

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

如果要防止同时运行两个相同types的块,则可以使用调度信号量。 信号量设置为1时,可以在发射块之前检查信号量,如果还在运行,则保释。 在块的结尾处,您发出信号灯以允许提交其他块。

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

if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0) { return; } dispatch_async(openGLESContextQueue, ^{ [EAGLContext setCurrentContext:context]; // Render here dispatch_semaphore_signal(frameRenderingSemaphore); }); 

frameRenderingSemaphore是在前面创build的,如下所示:

 frameRenderingSemaphore = dispatch_semaphore_create(1); 

如果您为每个选项卡的下载操作创build了一个类似的信号量,则可以进行检查以确保多个下载不会一次排列在该选项卡上。

你需要的是一个简单的布尔标志,以避免再次启动任务,直到它完成(根本不涉及GDC)。 类似于(伪代码,未经testing,免责声明等):

 - (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; } } 

这个伪代码可以用于asynchronousNSURLConnection之类的东西。 我还没有探索过GDC,有人需要适应GDC(你自己?)。

请注意,在这个例子中,我正在使用一个属性,而不是一个简单的variables访问。 这允许你在setter中实现更好的东西,比如激活活动指示器,禁用用户界面input等等。当父类中的variables的状态发生变化时,它也可以与子类一起工作。