为什么在主队列更新 UI 之后私有队列调度 _async 更新 UI?
Why private queue dispatch _async update UI after main queue update UI?
使用后台线程更新 UI 的理想方法是
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
});
});
但我们可以更新 UI 即使不使用主队列
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
//Run UI Updates
});
所以我正在使用 beizer 路径绘制一些点,这些点来自 iPad UIPanGestureRecognizer。现在我在主线程上绘制这些点并旋转这些点以获得新点并使用后台线程(并发)绘制这些新点。这是我的代码:
CGPoint touchPoint = [sender locationInView:self.view];
[pencilLayer[0] addPoint:touchPoint];
for(int i = 1; i < 4; i++)
{
dispatch_async(privateQueue, ^{
CGPoint point = Rotatepoint(500, 500, 45(degree), touchPoint);
[pencilLayer[i] addPoint:point];
});
}
我的问题是:
主线程和私有队列应该同时使用 UI。
为什么释放手势后,privateQueue在UI上画点?
嗯,根据 docs 通常最好将操作 UI 的代码保留在主线程上:
Threads and Your User Interface
If your application has a graphical user interface, it is recommended that you receive user-related events and initiate interface updates from your application’s main thread. This approach helps avoid synchronization issues associated with handling user events and drawing window content. Some frameworks, such as Cocoa, generally require this behavior, but even for those that do not, keeping this behavior on the main thread has the advantage of simplifying the logic for managing your user interface.
现在,在您的具体情况下,这可能正是您所发生的事情发生的原因。但是无论如何,在您的特定情况下,我认为没有充分的理由在私有队列上执行绘图。但是你应该将它保留在主线程中是有原因的 - 代码操作 UI,因此建议将它保留在主线程中(参见上面的参考资料)。此外,绘制点不是一项性能详尽的操作 - 没有充分的理由将其放在背景中。
所以我建议删除私有队列上的调度并简单地使用它:
CGPoint touchPoint = [sender locationInView:self.view];
[pencilLayer[0] addPoint:touchPoint];
for(int i = 1; i < 4; i++)
{
CGPoint point = Rotatepoint(500, 500, 45(degree), touchPoint);
[pencilLayer[i] addPoint:point];
}
此外,检查 this blog entry 关于线程和 UI。
您为每个点添加一个项目到后台队列。这应该不是很高效,并且可能会导致滞后。最好在后台队列中添加一个项目:
CGPoint touchPoint = [sender locationInView:self.view];
dispatch_async(privateQueue, ^{
[pencilLayer[0] addPoint:touchPoint];
for(int i = 1; i < 4; i++)
{
CGPoint point = Rotatepoint(500, 500, 45(degree), touchPoint);
[pencilLayer[i] addPoint:point];
}
});
这将一次绘制所有点。
使用后台线程更新 UI 的理想方法是
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
});
});
但我们可以更新 UI 即使不使用主队列
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
//Run UI Updates
});
所以我正在使用 beizer 路径绘制一些点,这些点来自 iPad UIPanGestureRecognizer。现在我在主线程上绘制这些点并旋转这些点以获得新点并使用后台线程(并发)绘制这些新点。这是我的代码:
CGPoint touchPoint = [sender locationInView:self.view];
[pencilLayer[0] addPoint:touchPoint];
for(int i = 1; i < 4; i++)
{
dispatch_async(privateQueue, ^{
CGPoint point = Rotatepoint(500, 500, 45(degree), touchPoint);
[pencilLayer[i] addPoint:point];
});
}
我的问题是: 主线程和私有队列应该同时使用 UI。 为什么释放手势后,privateQueue在UI上画点?
嗯,根据 docs 通常最好将操作 UI 的代码保留在主线程上:
Threads and Your User Interface
If your application has a graphical user interface, it is recommended that you receive user-related events and initiate interface updates from your application’s main thread. This approach helps avoid synchronization issues associated with handling user events and drawing window content. Some frameworks, such as Cocoa, generally require this behavior, but even for those that do not, keeping this behavior on the main thread has the advantage of simplifying the logic for managing your user interface.
现在,在您的具体情况下,这可能正是您所发生的事情发生的原因。但是无论如何,在您的特定情况下,我认为没有充分的理由在私有队列上执行绘图。但是你应该将它保留在主线程中是有原因的 - 代码操作 UI,因此建议将它保留在主线程中(参见上面的参考资料)。此外,绘制点不是一项性能详尽的操作 - 没有充分的理由将其放在背景中。
所以我建议删除私有队列上的调度并简单地使用它:
CGPoint touchPoint = [sender locationInView:self.view];
[pencilLayer[0] addPoint:touchPoint];
for(int i = 1; i < 4; i++)
{
CGPoint point = Rotatepoint(500, 500, 45(degree), touchPoint);
[pencilLayer[i] addPoint:point];
}
此外,检查 this blog entry 关于线程和 UI。
您为每个点添加一个项目到后台队列。这应该不是很高效,并且可能会导致滞后。最好在后台队列中添加一个项目:
CGPoint touchPoint = [sender locationInView:self.view];
dispatch_async(privateQueue, ^{
[pencilLayer[0] addPoint:touchPoint];
for(int i = 1; i < 4; i++)
{
CGPoint point = Rotatepoint(500, 500, 45(degree), touchPoint);
[pencilLayer[i] addPoint:point];
}
});
这将一次绘制所有点。