Ios 调度异步(调度获取主队列(),^{…});等到完成?
我在我的应用程序中有一个场景,我想在一个方法中执行一些耗时的任务,包括一些数据处理和UI更新。我的方法是这样的Ios 调度异步(调度获取主队列(),^{…});等到完成?,ios,objective-c,multithreading,grand-central-dispatch,dispatch-async,Ios,Objective C,Multithreading,Grand Central Dispatch,Dispatch Async,我在我的应用程序中有一个场景,我想在一个方法中执行一些耗时的任务,包括一些数据处理和UI更新。我的方法是这样的 - (void)doCalculationsAndUpdateUIs { // DATA PROCESSING 1 // UI UPDATE 1 // DATA PROCESSING 2 // UI UPDATE 2 // DATA PROCESSING 3 // UI UPDATE 3 } - (void)doCalculat
- (void)doCalculationsAndUpdateUIs {
// DATA PROCESSING 1
// UI UPDATE 1
// DATA PROCESSING 2
// UI UPDATE 2
// DATA PROCESSING 3
// UI UPDATE 3
}
- (void)doCalculationsAndUpdateUIs {
// DATA PROCESSING 1
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 1
});
/* I expect the control to come here after UI UPDATE 1 */
// DATA PROCESSING 2
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 2
});
/* I expect the control to come here after UI UPDATE 2 */
// DATA PROCESSING 3
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 3
});
}
因为这很耗时,我想在后台线程上使用
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
但是由于数据处理和UI更新都采用相同的方法,所以我只想使用
dispatch_async(dispatch_get_main_queue(), ^{
最后我的方法是这样的
- (void)doCalculationsAndUpdateUIs {
// DATA PROCESSING 1
// UI UPDATE 1
// DATA PROCESSING 2
// UI UPDATE 2
// DATA PROCESSING 3
// UI UPDATE 3
}
- (void)doCalculationsAndUpdateUIs {
// DATA PROCESSING 1
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 1
});
/* I expect the control to come here after UI UPDATE 1 */
// DATA PROCESSING 2
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 2
});
/* I expect the control to come here after UI UPDATE 2 */
// DATA PROCESSING 3
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 3
});
}
这真的有效吗?这真的是一种好的做法吗?实现这一目标的最佳方式是什么
另外,所有这三个操作都是相互关联的
编辑:对不起,伙计们。我在上述代码中遗漏了一行。我的实际代码如下所示
- (void)doCalculationsAndUpdateUIs {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// DATA PROCESSING 1
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 1
});
/* I expect the control to come here after UI UPDATE 1 */
// DATA PROCESSING 2
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 2
});
/* I expect the control to come here after UI UPDATE 2 */
// DATA PROCESSING 3
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATE 3
});
});
}
再一次,我真的为这一困惑道歉。不,它不会等待,而且您在该示例中执行此操作的方式不是好的做法
dispatch\u async
始终是异步的。只是将所有UI块排队到同一队列中,这样不同的块将按顺序运行,但与数据处理代码并行
如果要等待更新,可以改用dispatch\u sync
// This will wait to finish
dispatch_sync(dispatch_get_main_queue(), ^{
// Update the UI on the main thread.
});
另一种方法是嵌套块排队。不过,我不建议将其用于多个级别
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Background work
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
});
});
});
});
如果需要更新UI以等待,则应使用同步版本。让一个后台线程等待主线程是可以的。UI更新应该非常快。不,它不会等待
您可以使用
performSelectorOnMainThread:withObject:waitUntilDone:
您必须将主队列调度放在运行计算的块中。例如(这里我创建了一个调度队列,而不使用全局队列):
当然,如果您创建了一个队列,如果您的目标是6.0之前的iOS版本,请不要忘记
dispatch\u release
。您建议的doccalculations和updateuis
执行数据处理并将UI更新发送到主队列。我假设您在第一次调用时已将doccalculationsandUpdateUI
调度到后台队列
虽然技术上很好,但这有点脆弱,这取决于您每次调用它时都记得将其分派到后台:相反,我建议您将其分派到后台,然后从同一个方法中分派回主队列,因为它使逻辑更加明确和健壮,等等
因此,它可能看起来像:
- (void)doCalculationsAndUpdateUIs {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
// DATA PROCESSING 1
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATION 1
});
/* I expect the control to come here after UI UPDATION 1 */
// DATA PROCESSING 2
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATION 2
});
/* I expect the control to come here after UI UPDATION 2 */
// DATA PROCESSING 3
dispatch_async(dispatch_get_main_queue(), ^{
// UI UPDATION 3
});
});
}
关于您是使用dispatch\u async
(后台进程将不等待UI更新)异步发送UI更新,还是使用dispatch\u sync
(后台进程将等待UI更新)同步发送UI更新,问题是为什么要同步进行:您真的想在后台进程等待UI更新时减慢它,还是希望在UI更新发生时后台进程继续进行
通常,您会使用dispatch\u async
异步调度UI更新,就像您在原始问题中使用的那样。是的,在某些特殊情况下,您当然需要同步地分派代码(例如,您通过在主队列上对某个类属性执行所有更新来同步对该类属性的更新),但通常情况下,您只是异步分派UI更新并继续。如果做得太草率,同步发送代码可能会导致问题(例如死锁),因此我的总建议是,如果有迫切的需要,您可能只应该同步发送UI更新,否则您应该设计解决方案,以便可以异步发送它们
在回答您关于这是否是“实现这一目标的最佳方式”的问题时,我们很难在不了解更多有关正在解决的业务问题的情况下说出来。例如,如果您可能多次调用此
doccalculations和updateuis
,我可能倾向于使用自己的串行队列而不是并发全局队列,以确保这些队列不会相互重叠。或者,如果您可能需要在用户解除场景或再次调用该方法时取消此doccalculationsandUpdateUI
,那么我可能倾向于使用提供取消功能的操作队列。这完全取决于你想要实现什么
但是,一般来说,将复杂任务异步分派到后台队列,然后将UI更新异步分派回主队列的模式非常常见。好的,有两种方法:
// GLOBAL_CONCURRENT_QUEUE
- (void)doCalculationsAndUpdateUIsWith_GlobalQUEUE
{
dispatch_queue_t globalConcurrentQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalConcurrentQ, ^{
// DATA PROCESSING 1
sleep(1);
NSLog(@"Hello world chekpoint 1");
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 1
sleep(1);
NSLog(@"Hello world chekpoint 2");
});
/* the control to come here after UI UPDATION 1 */
sleep(1);
NSLog(@"Hello world chekpoint 3");
// DATA PROCESSING 2
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 2
sleep(1);
NSLog(@"Hello world chekpoint 4");
});
/* the control to come here after UI UPDATION 2 */
sleep(1);
NSLog(@"Hello world chekpoint 5");
// DATA PROCESSING 3
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 3
sleep(1);
NSLog(@"Hello world chekpoint 6");
});
});
}
// SERIAL QUEUE
- (void)doCalculationsAndUpdateUIsWith_GlobalQUEUE
{
dispatch_queue_t serialQ = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_async(serialQ, ^{
// DATA PROCESSING 1
sleep(1);
NSLog(@"Hello world chekpoint 1");
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 1
sleep(1);
NSLog(@"Hello world chekpoint 2");
});
sleep(1);
NSLog(@"Hello world chekpoint 3");
// DATA PROCESSING 2
dispatch_sync(dispatch_get_main_queue(), ^{
// UI UPDATION 2
sleep(1);
NSLog(@"Hello world chekpoint 4");
});
});
}
如果要运行单个独立排队操作,而不关心其他并发操作,则可以使用全局并发队列:
dispatch_queue_t globalConcurrentQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
这将返回一个具有给定优先级的并发队列,如文档中所述:
调度\队列\优先级\调度到队列的高优先级项目将以高优先级运行,即队列将被安排在任何默认优先级或低优先级队列之前执行
调度\队列\优先级\调度到队列的默认项目将以默认优先级运行,即在调度所有高优先级队列之后,但在调度任何低优先级队列之前,将调度队列以执行
调度\队列\优先级\调度到队列的低优先级项目将以低优先级运行,即在调度所有默认优先级和高优先级队列后,将调度队列执行
调度\u队列\u优先级\u调度到队列的后台项目将以后台优先级运行,即在调度所有更高优先级的队列之后,队列将被调度为执行,并且系统将以thre方式运行此队列上的项目
dispatch_group_t imageGroup = dispatch_group_create();
dispatch_group_enter(imageGroup);
[uploadImage executeWithCompletion:^(NSURL *result, NSError* error){
// Image successfully uploaded to S3
dispatch_group_leave(imageGroup);
}];
dispatch_group_enter(imageGroup);
[setImage executeWithCompletion:^(NSURL *result, NSError* error){
// Image url updated
dispatch_group_leave(imageGroup);
}];
dispatch_group_notify(imageGroup,dispatch_get_main_queue(),^{
// We get here when both tasks are completed
});