How-to find out what causes a didHideZoomSlider error on IOS 8?

21

The following error keeps coming up in my app's crashlytics logs

on IOS 8:

libobjc.A.dylib objc_msgSend + 5 didHideZoomSlider:

Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x0000000e 

I have no clue where to start? Anybody an idea on what I should be looking for?

The whole stacktrace :

 0
libobjc.A.dylib     
objc_msgSend + 5 
didHideZoomSlider:
1 Foundation    
__NSFireDelayedPerform + 468
2
CoreFoundation  
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
3
CoreFoundation  
__CFRunLoopDoTimer + 650
4
CoreFoundation  
__CFRunLoopRun + 1418
5
CoreFoundation  
CFRunLoopRunSpecific + 456
6
    CoreFoundation  
CFRunLoopRunInMode + 106
7
GraphicsServices    
GSEventRunModal + 136
8
UIKit   
UIApplicationMain + 1440
9
main.m line 8
main

Does the error msg mean that something is going wrong with an ImagePickerCameraView ?

I also sometimes get

 Crashed: com.apple.main-thread
 EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0xeec1ff5e
 0 libobjc.A.dylib  objc_msgSend + 21 didHideZoomSlider:

If ImagePicker is the troublemaker here is an code excerpt :

- (IBAction)onTakePictureToolbarButtonPushed:(id)sender {
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    [imagePicker setSourceType:
        [UIImagePickerController  isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]
            ? UIImagePickerControllerSourceTypeCamera
            : UIImagePickerControllerSourceTypePhotoLibrary
    ];

    [imagePicker setDelegate:self];
    [self presentViewController:imagePicker animated:YES completion:nil];
}



- (void)imagePickerController: (UIImagePickerController *)picker didFinishPickingMediaWithInfo: (NSDictionary *)info {
UIImage* rawImage = [info objectForKey: UIImagePickerControllerOriginalImage];

NSData *imageData = UIImageJPEGRepresentation(rawImage, 0.3);
[imageData writeToFile: @"img.jpg" atomically: YES];

[self dismissViewControllerAnimated: YES completion:nil];
[self.tableView reloadData];

}
ios
ios8
crashlytics
asked on Stack Overflow Nov 10, 2014 by jack • edited Nov 12, 2014 by jack

3 Answers

29

I've been able to replicate this issue in my code. This seems to be a bug in Apple's code and is a timing issue.

I haven't replicated it by clicking to actually take a photo, but I can replicate it when I hit cancel. You can try doing this in your code and seeing if it works for you. Open up the camera to take a photo and then pinch to zoom. You'll get a little zoom slider show up on the screen. After about 4-5 second that zoom slide fades away. This is where timing comes in. If you click cancel just as it starts to fade you can get it to crash.

My assumption is that Apple has an animation block in which it fades the zoom slider. In the completion of that animation it calls didHideZoomSlider: without checking it's reference to the image picker.

I think it is easier to replicate on my cancel code because it was very simple:

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [self dismissViewControllerAnimated:YES completion:nil];
}

My assumption is that since this executes so fast it is able to dismiss it in the middle of that animation. Therefore my solution is to actually delay my dismissal of the view by a small amount of time.

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    __weak typeof(self) wSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [wSelf dismissViewControllerAnimated:YES completion:nil];
    });
}

I don't think this "fixes" the issue, but reduces it such that I'm unable to replicate it anymore. This should be filed as a bug with Apple (which I'll do next).

Update: Sent to Apple.

answered on Stack Overflow Nov 12, 2014 by RyanJM • edited Nov 13, 2014 by RyanJM
13

I didn't have much luck with adding the delay. Crashes still occurred in my case (iOS 8 and 9.0.1).

There's an OpenRadar that suggests removing the delegate of the CAMZoomSlider likely responsible for the crash, and this worked well for me.

User beware, though, as this manipulates a private class and may result in an App Store submission rejection...

To fix issue with delegate, subclass UIImagePickerController and add the following:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self clearZoomSliderDelegateForClass:[self sliderClass] subviews:self.view.subviews];
}

- (void)clearZoomSliderDelegateForClass:(Class)sliderClass subviews:(NSArray *)subviews {
    for (UIView *subview in subviews) {
        if ([subview isKindOfClass:sliderClass] && [subview respondsToSelector:@selector(setDelegate:)]) {
            [subview performSelector:@selector(setDelegate:) withObject:nil];
            return;
        }
        else {
            [self clearZoomSliderDelegateForClass:sliderClass subviews:subview.subviews];
        }
    }
}

- (Class)sliderClass {
    for (NSString* prefix in @[@"CAM", @"CMK"]) {
        Class zoomClass = NSClassFromString([prefix stringByAppendingString:@"ZoomSlider"]);
        if (zoomClass != Nil) {
            return zoomClass;
        }
    }
    return Nil;
}

In iOS 9 SDK private CameraKit framework prefix changed from CAM to CMK (just check slider with visual debugger), so previous workaround had to be updated.

This crash may also look like this in logs:

0   libobjc.A.dylib                      0x3591fae6 objc_msgSend + 6
1   Foundation                           0x24d28e59 __NSFireDelayedPerform + 466
...
answered on Stack Overflow Apr 30, 2015 by adamup • edited Oct 1, 2015 by adamup
0

This is already answered, but another potential solution here would be to retain the image picker controller instance inside the view controller to avoid it being deallocated prior to apple's callback firing.

answered on Stack Overflow Jul 16, 2015 by shawnwall

User contributions licensed under CC BY-SA 3.0