1

I have a tab-based app with 2 tabs: the first one performs multiple operations in a background thread (downloading json) and updates the UI on the main thread when the fetching is over. The second tab presents a camera as soon as it appears. When I open the app, the fetching starts in background in tab #1. If I switch to tab #2 while in the background thread in tab 1, the camera loads. If I wait until the main thread updated the UI (still tab 1) before switching to tab 2, the camera takes 10 seconds to load, only showing a black screen. What's even more weird is that the NSLogs tell me the camera is supposed to be already loaded, but a black screen shows up. My question is, is there a way to "clear" the main thread when tab #2 appears, or even better, is there a way to show the camera as a high priority task in the main thread?

This is the code in ViewDidAppear (Tab 2):

 dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"4");
        [self showImagePickerForSourceType:UIImagePickerControllerSourceTypeCamera];
    });

Next:

- (void)showImagePickerForSourceType:(UIImagePickerControllerSourceType)sourceType
{
    NSLog(@"5");

    dispatch_async(dispatch_get_main_queue(), ^{

        NSLog(@"6");

        [[UIApplication sharedApplication] setStatusBarHidden:YES];

        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
        {
            NSLog(@"7");

            imagePickerController = [[UIImagePickerController alloc] init];
            imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
            imagePickerController.sourceType = sourceType;
            imagePickerController.delegate = self;
            imagePickerController.showsCameraControls = NO;

//            NSLog(@"HERE");


            if (isiPhone5)
            {
                NSLog(@"8");

                [[NSBundle mainBundle] loadNibNamed:@"OverlayView" owner:self options:nil];
            }
            else
            {
                NSLog(@"not 5");
                [[NSBundle mainBundle] loadNibNamed:@"Over2" owner:self options:nil];
            }

            self.overlayView.frame = imagePickerController.cameraOverlayView.frame;
            imagePickerController.cameraOverlayView = self.overlayView;
            self.overlayView = nil;


            self.imagePickerController = imagePickerController;
            [self presentViewController:self.imagePickerController animated:NO completion:nil];
            NSLog(@"9 DONE");
        }
    });

}
anthoprotic
  • 827
  • 2
  • 13
  • 24

2 Answers2

0

Seeing log output doesn't necessarily mean that your camera view is visible, hence why there is a completion block provided to you in the presentViewController:animated:completion: method. Have you tried putting some code there to see when that's run?

This is the kind of problem that the time profiler tool in instruments was designed for. If you haven't already, I highly suggest investigating with that tool, as it can basically pinpoint what's causing the lag in your app.

JJC
  • 1,346
  • 10
  • 10
  • Hey, I tried logging a message when the camera is presented like this: "completion:^{NSLog(@"SHOW");}];". The weird thing is, "Show" appears in the console even if the black screen is showing. Eventually (sometimes 30 seconds later) the camera appears but "Show" doesn't get called. Which would mean the app thinks the camera was already presented… – anthoprotic Mar 11 '14 at 16:14
  • As for Time Profiler, another weird thing. The time spent on the main thread to present the camera is the same when the camera is showing as when I have a 20 seconds black screen before (about 200 ms). What does that confirm? – anthoprotic Mar 11 '14 at 16:15
  • As you've probably already guessed, that shows that it's likely not a blocking call in the main thread that's causing the lag. It could be something as simple as an alpha value being set in an animation block somewhere. Do you do any kind of view manipulation with the camera view? Also, if you post the log of the time slice from instruments where you load the camera view, that might help us shed more light on the problem for you. – JJC Mar 11 '14 at 22:45
  • Here is the link to the Time Profiler image: http://imgur.com/NLvxOm0 I opened the camera at 0:10, and it showed a black screen until 0:30. Also, I am in fact setting an alpha value to 0.9 on my custom overlay, but it's not the problem because 1) if I set the alpha to 1 and even remove the overlay the camera is stilt not showing and 2) I followed Apple's example here: http://bit.ly/1kgU6Eh – anthoprotic Mar 12 '14 at 05:22
  • You know what, I am starting to be convinced that this is a thread problem. Why is that? In tab 1 I'm doing multiple requests in the background, and updating UI in the main thread. If I juste remove the dispatch_async queue code and let the fetching/parsing in the main thread (thus blocking the app for 1 second), now the camera works fine at all time. I'm really not sure I'm using the background thread the right way, see image: http://imgur.com/om3mjCN I just needed a quick way to fetch data from core data + https server (2 threads) in the background - should I look into NSOperation/NSTread? – anthoprotic Mar 12 '14 at 05:28
  • Swapping in NSOperation is likely not going to solve the problem, but it's worth noting that by passing in NULL to dispatch_queue_create, you are indicating that the operations should occur serially. Although your code doesn't indicate this, it can be possible that if you're queuing up a bunch of operations, then finally queue up the operation that calls showImagePickerForSourceType, you'll see a delay. Sorry I can't be of more help. – JJC Mar 12 '14 at 07:11
0

I posted an answer here (iOS 7 UIImagePicker preview black screen) that may be a temporary solution to your issue. Essentially the UIImagePickerController has a memory leak in iOS 7, meaning that it'll get slower and slower with each instantiation until you have 10+ seconds of black screen while you wait for the camera to load.

As mentioned in the link above, I recommend subclassing UIImagePickerController or just making it an instance variable in your ViewController so its ever only instantiated once.

I know you're looking for an answer more along the lines of "clearing the main queue", but hopefully this will help you out in the meantime.

Community
  • 1
  • 1
ebandersen
  • 2,362
  • 26
  • 25
  • Hey, I actually had read your solution before, but this is not the issue because the problem happens even at the first load of the app. The problem appears to be really random though - sometimes in the main thread, sometimes in the background thread. – anthoprotic Mar 11 '14 at 16:14
  • Ahhhh .. Yeah, I'm not sure what the issue is then :P – ebandersen Mar 11 '14 at 16:15