Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dispatch_async has lag somewhere, can't find where. is there an NSLog problem?

So i have this code:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

//Bunch of code

NSLog(@"Test");

});

which runs and returns nslog immediately. But the results of the code only appear on the screen a few seconds delay. Is there a problem with nslog being used here, which means it's called before it would usually, making it seem speedy when really it isn't. I'm confused as to where this delay is coming from, as the NSLog is right at the end of all the code which runs then.

Also, another solution to my problem, is it possible to get an NSLog when every method is called (a bit like NSZombiesEnabled i suppose) so i can make sure there isn't some bit which i didn't notice taking up the sweet response time of my app?

like image 619
Andrew Avatar asked Aug 08 '11 18:08

Andrew


2 Answers

Recently I had a similar problem myself. Most likely your delayed updates are stuff you are doing on the user interface. And here's the problem: you are not running in the main thread of the application (also called the UI thread). Therefore, whatever you change to the user interface won't actually be visible until... it feels like showing up, which tends to happen with a redraw triggered by something else in the application.

What you have to do is inside your block queue your graphical updates in the UI thread like this:

dispatch_async(dispatch_get_main_queue(), ^{
        // Do GUI stuff.
    });

Sometimes your block might be big or just using code which was previously run on the main thread, so it is difficult to move all of it to a specific place to run it on the main queue. For these situations, queue a forced refresh in the UI thread at the end of your block:

dispatch_async(dispatch_get_main_queue(), ^{
        [self.somewidget setNeedsDisplay];
        [self.view setNeedsDisplay];
        [self.dontforgetme setNeedsDisplay];
    });

With regards to your "app taking up the sweet response time of my app", it seems that you are trying to use GDC to avoid blocking the user interface. To make sure programatically that you don't happen to do CPU intensive operations in the UI thread, and vice versa, you run GUI updates in the UI block, I've made myself the following macros:

/// Stick this in code you want to assert if run on the main UI thread.
#define DONT_BLOCK_UI() \
    NSAssert(![NSThread isMainThread], @"Don't block the UI thread please!")

/// Stick this in code you want to assert if run on a background thread.
#define BLOCK_UI() \
    NSAssert([NSThread isMainThread], @"You aren't running in the UI thread!")

As you can see by the comments, I tend to use these macros at the beginning of methods I want to make sure I'm not using by error in the wrong place. I've put these macros and more random stuff at https://github.com/gradha/ELHASO-iOS-snippets which you may find useful.

like image 69
Grzegorz Adam Hankiewicz Avatar answered Oct 16 '22 06:10

Grzegorz Adam Hankiewicz


UIKit isn’t thread-safe. Any calls you make that affect your UI need to be made on the main thread, or you’ll get weird, unpredictable behavior. Example:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Background code that doesn't need to update the UI here

    dispatch_async(dispatch_get_main_queue(), ^{
        // UI code here
    });
});
like image 22
Noah Witherspoon Avatar answered Oct 16 '22 06:10

Noah Witherspoon