Search code examples
iosuikituiimagepickercontrollergrand-central-dispatchios-multithreading

Does didFinishPickingMediaWithInfo get called in background thread?


I thought that the UIImagePickerController delegate methods (or any UIKit delegate method) get called in the main thread. But here, when picking image from gallery or camera, the didFinishPickingMediaWithInfo method does not seem to get called in one, and UIKit delegate methods must be called on main thread right? Dispatching explicitly to main thread works. There are no mentions about this in the Apple documentation as well.

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString* ,id> *)info{

    uploadImage = info[UIImagePickerControllerOriginalImage]; // Set selected image            
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.leftButton setImage:[UIImage imageNamed:@"image_attach.png"]
                         forState:UIControlStateNormal];
    });

    // The following does not work.
    //[self.leftButton setImage:[UIImage imageNamed:@"image_attach.png"]
                     //forState:UIControlStateNormal];  
}

Bottom line, do all UIKit delegate methods get called on main thread? Or some get called in non-main thread? Why this inconsistency where we BELIEVE that there is no necessity to dispatch our code to main thread, but in the end doing that makes things work? If someone knows the answer please clarify.

EDIT: As suggested by Rob, I checked with this method [NSThread isMainThread] to see in which thread the code gets executed. It clearly returned true to confirm that I am in the main thread, but strangely without dispatching my setImage method to main queue explicitly, the code does not work. Also, I tried moving my code to the picker's dismiss method's completion handler, voila it works without an explicit main thread block!

Still confused on why this is behaving like this...


Solution

  • When I tested it, it was called on the main thread. I'd suggest checking [NSThread isMainThread] to confirm (or, in Swift, dispatchPrecondition(condition: .onQueue(.main)) or Thread.isMainThread). In my test, it was on the main thread.

    If it's not the main thread (!), I'd check where you present it, to make sure you presented it from the main thread.

    I can't think of any UI-related delegate methods that are called on a background thread. For non UI delegate methods, there are plenty that don't use the main thread, but UI-centric API like this use the main thread.