Question

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?

Was it helpful?

Solution

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]);
    }];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top