iosobjective-cmultithreadingios-multithreading

Why private queue dispatch _async update UI after main queue update UI?


The ideal way to update UI using background thread is

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});

But we can update UI even without using main queue using

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    //Run UI Updates
});

So I am using beizer path to draw some points and those points are coming from iPad UIPanGestureRecognizer. Now I draw those points on main thread and also rotate those points to get new points and draw those new points using background thread(concurrent). Here is my code:

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];
    });
}

My Question is: The main thread and private queue should draw on UI simultaneously. Why after releasing the gesture, privateQueue draw points on UI?


Solution

  • Well, according to the docs usually it is best to keep code that manipulates UI on the main thread:

    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.

    Now in your specific case it might be exactly the reason why happens what happens for you. But anyway, in your particular case I see no good reason to perform drawing on a private queue. But there are reasons why you should keep it on main thread - the code manipulates UI, so it is recommended to keep it on main thread (see reference above). Moreover, the point drawing is NOT a performance exhaustive operation - there is no good reason to put it on background.

    So I recommend removing that dispatch on private queue and simply use this:

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

    Also, check this blog entry about threading and UI.