Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dismissing a MFMailComposeViewController causes EXC_BAD_ACCESS

I'm displaying a MFMailComposeViewController like so:

- (IBAction) contactUs: (id) sender {
    [Tracker trackContactUsPressed: [MFMailComposeViewController canSendMail]];

    if ([MFMailComposeViewController canSendMail] == NO) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Email Error"
                                                        message: @"Email has not been configured on this device.  Please send us an email at\[email protected]"
                                                       delegate: self
                                              cancelButtonTitle: @"OK"
                                              otherButtonTitles: nil];
        [alert show];
        [alert release];
    } else {

        MFMailComposeViewController *controller = [[[MFMailComposeViewController alloc] init] autorelease];

        [controller setSubject:@"Comments about FOO"];            

        [controller setToRecipients: [NSArray arrayWithObject: @"[email protected]"]];
        [controller setMailComposeDelegate: self];

        [[self parentViewController] presentModalViewController:controller animated:YES];
    }
}

Then my delegate looks like this:

- (void) mailComposeController: (MFMailComposeViewController *) controller didFinishWithResult: (MFMailComposeResult) result error: (NSError *) error {
    [[self parentViewController] dismissModalViewControllerAnimated: YES];
}

However as soon as the delegate is called, and the view disappears, I get a EXC_BAD_ACCESS. The backtrace says this:

#0  0x00000000 in ?? ()
#1  0x0065a2d9 in -[UIWindowController transitionViewDidComplete:fromView:toView:] ()
#2  0x0044a905 in -[UITransitionView notifyDidCompleteTransition:] ()
#3  0x003f1499 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
#4  0x003f132b in -[UIViewAnimationState animationDidStop:finished:] ()
#5  0x02631db0 in run_animation_callbacks ()
#6  0x02631c6f in CA::timer_callback ()
#7  0x0284bf73 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ()
#8  0x0284d5b4 in __CFRunLoopDoTimer ()
#9  0x027a9dd9 in __CFRunLoopRun ()
#10 0x027a9350 in CFRunLoopRunSpecific ()
#11 0x027a9271 in CFRunLoopRunInMode ()
#12 0x0305500c in GSEventRunModal ()
#13 0x030550d1 in GSEventRun ()
#14 0x003cfaf2 in UIApplicationMain ()
#15 0x000023c5 in main (argc=1, argv=0xbfffefcc) at main.m:14

I can't seem to figure out what's wrong. As far as I know, this worked previously with the 3.x SDK we were using (we released it and everything!). Now with the new SDK (4.1) it seems to fail. I'm not sure if that's related.

Does anyone know what's wrong?

like image 681
Tom Gwozdz Avatar asked Jan 22 '23 04:01

Tom Gwozdz


2 Answers

I found the problem.

We're using a library called ShareKit to do some Twitter and Facebook integration. Since we already had our own email form, we didn't need ShareKit to handle it for us, so we deleted the ShareKit's email handling files.

All was well, except that in its initialization, ShareKit does this:

SHKSwizzle([MFMailComposeViewController class], @selector(viewDidDisappear:), @selector(SHKviewDidDisappear:)); 

Where SHKSwizzle basically replaces MFMailComposerViewController's viewDidDisappear: method with SHKviewDidDisappear: (Don't ask me why... I think that's horrible).

Anyway, it turns out that SHKviewDidDisappear was in ShareKit's mail handler, so deleting the file how makes the code jump to hyperspace and crash horribly. Restoring the file again fixes the problem.

Ugh.

Thanks everyone for your help!

like image 151
Tom Gwozdz Avatar answered Mar 30 '23 19:03

Tom Gwozdz


Just a hunch, but what looks odd to me are these lines:

[[self parentViewController] presentModalViewController:controller animated:YES];

and

[[self parentViewController] dismissModalViewControllerAnimated: YES];

True, I don't know about your arrangement of view controllers, but isn't it a little unusual to reference [self parentViewController] directly? You're heavily coupling three view controllers (the caller, the parent, and the modal view); this discourages code/view controller reusability (e.g. if you wanted to reuse the same view controller inside a different view hierarchy elsewhere in the app).

The only reason I can imagine you may want to do this is that the parent is a UINavigationController/UITabBarController, and since that is the top view, you want that view controller to be presenting the modal.

In this case I use:

[[self navigationController] presentModalViewController:controller animated:YES]

Or better yet, in a Tab Bar situation, I have my root view controller register an observer listening for notifications, and then all modals are launched from the root view controller.

Could I get a little more detail about your view stack? Also, could you try once just calling on "self" instead of the parent and see what happens?

like image 27
makdad Avatar answered Mar 30 '23 19:03

makdad