Emp*_*ack 44 multithreading objective-c grand-central-dispatch ios dispatch-async
我的应用程序中有一个场景,我想在一个方法中做一些耗费时间的任务,其中包括一些数据处理和UI更新.我的方法看起来像这样,
- (void)doCalculationsAndUpdateUIs {
    // DATA PROCESSING 1
    // UI UPDATE 1
    // DATA PROCESSING 2
    // UI UPDATE 2
    // DATA PROCESSING 3
    // UI UPDATE 3
} 
由于耗时我想在后台线程上进行数据处理,使用,
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{
但由于数据处理和UI更新都采用相同的方法,我只想在主线程中使用UI更新,
dispatch_async(dispatch_get_main_queue(), ^{
最后我的方法看起来像这样,
- (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
    });
}
这真的有用吗?这真的是一个好习惯吗?实现这一目标的最佳方法是什么?
PS所有这三个操作都是相互关联的.
编辑:对不起伙计们.我错过了上面代码中的一行.我的实际代码看起来像这样.
- (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
        });
    });
}
再一次,我真的为这种混乱道歉.
Dav*_*ist 111
不,它不等待,你在那个样本中做的方式不是好习惯.
dispatch_async永远是异步的.只是您将所有UI块排入同一队列,因此不同的块将按顺序运行,但与您的数据处理代码并行.
如果您希望更新等待,则可以使用dispatch_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更新应该非常快.
Sta*_*ort 12
您必须将主队列调度放在运行计算的块中.例如(这里我创建一个调度队列,不使用全局队列):
dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_async(queue, ^{
  // Do some computation here.
  // Update UI after computation.
  dispatch_async(dispatch_get_main_queue(), ^{
    // Update the UI on the main thread.
  });
});
当然,如果你创建一个队列,不要忘记dispatch_release你是否在6.0之前定位iOS版本.
您建议进行doCalculationsAndUpdateUIs数据处理并将UI更新分派给主队列.我假设您doCalculationsAndUpdateUIs在第一次调用后已调度到后台队列.
虽然技术上很好,但这有点脆弱,取决于你每次打电话时都记得将它发送到后台:相反,我会建议你将你的调度发送到后台并从同一时间发送回主队列.方法,因为它使逻辑明确,更健壮,等等.
因此它可能看起来像:
- (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
        });
    });
}
在是否你与异步派遣你的UI更新条款dispatch_async(其中后台进程将不会等待UI更新)或同步地dispatch_sync(它会等待UI更新),问题是为什么会要同步做到这一点:您是否真的希望在等待UI更新时减慢后台进程,或者您希望在UI更新发生时继续进行后台进程.
通常,您将dispatch_async使用在原始问题中使用的异步方式调度UI更新.是的,确实存在需要同步调度代码的特殊情况(例如,您通过在主队列上执行对其的所有更新来将更新同步到某个类属性),但通常情况下,您只需调度UI更新异步并继续.同步调度代码可能会导致问题(例如死锁),所以我的总法律顾问是,如果有一些迫切的需要,你应该只能同步调度UI更新,否则你应该设计你的解决方案,这样你就可以异步调度它们.
在回答您关于这是否是"实现这一目标的最佳方式"的问题时,我们很难在不了解更多有关正在解决的业务问题的情况下说出来.例如,如果您可能doCalculationsAndUpdateUIs多次调用此方法,我可能倾向于使用自己的串行队列而不是并发全局队列,以确保它们不会相互跳过.或者,如果您可能需要能够doCalculationsAndUpdateUIs在用户解除场景或再次调用该方法时取消此操作,那么我可能倾向于使用提供取消功能的操作队列.这完全取决于你想要实现的目标.
但是,通常,将复杂任务异步调度到后台队列然后异步调度UI更新回主队列的模式非常常见.
| 归档时间: | 
 | 
| 查看次数: | 105032 次 | 
| 最近记录: |