cyborg86pl
cyborg86pl

Reputation: 2617

iOS NSNotificationCenter strange delay

In my app i need to detect whether ImagePicker is ready to take photo. I found a solution here: How to know if iPhone camera is ready to take picture?

So i've got this code in viewDidLoad:

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(showButton:)
name:AVCaptureSessionDidStartRunningNotification object:nil];

and selector looks like this:

- (void)showButton:(NSNotification *)notification{

    NSLog(@"---CAMERA READY");

    [button setHidden:NO];
    [button setAlpha:0.0];
    [button setTransform:CGAffineTransformScale(CGAffineTransformIdentity, 1.5, 1.5)];

    [UIView animateWithDuration:.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
        [button setAlpha:1.0];
        [button setTransform:CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0)];
    } completion:^(BOOL finished) {

    }];

    NSLog(@"---CAMERA READY");

}

And here is something strange happening, because both NSLogs shows up immediately, but whole button animation fires even 30 secs after.

Does UIView updates separately? How do i sync both logs and animation?

Upvotes: 1

Views: 2085

Answers (1)

Mick MacCallum
Mick MacCallum

Reputation: 130222

Going to put this in the answer box for future users to see..

What you're experiencing makes it look like your notification isn't being called on the main thread, and updating the UI on a background thread is undefined behavior. The cure for this is simple, just wrap the contents of your method in a dispatch_async() call and send everything back to the main queue.

- (void)showButton:(NSNotification *)notification {

    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"---CAMERA READY");

        [button setHidden:NO];
        [button setAlpha:0.0];
        [button setTransform:CGAffineTransformScale(CGAffineTransformIdentity, 1.5, 1.5)];

        [UIView animateWithDuration:.2 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            [button setAlpha:1.0];
            [button setTransform:CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0)];
        } completion:nil];

        NSLog(@"---CAMERA READY");
    });
}

As an alternative, you can just use a different NSNotificationCenter instance method. Specifically, -addObserverForName:object:queue:usingBlock: allows you to specify which operation queue the callback block should be executed on. In this case, you'd want to pass [NSOperationQueue mainQueue];.

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html#//apple_ref/occ/instm/NSNotificationCenter/addObserverForName:object:queue:usingBlock:

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
self.localeChangeObserver = [center addObserverForName:NSCurrentLocaleDidChangeNotification object:nil
    queue:mainQueue usingBlock:^(NSNotification *note) {

        NSLog(@"The user's locale changed to: %@", [[NSLocale currentLocale] localeIdentifier]);
    }];

Upvotes: 2

Related Questions