Sasha Grievus
Sasha Grievus

Reputation: 2686

Why calling MFMailComposeViewController deallocates the view that called it?

I have this simple function to write mail on ios 8.0, xcode 6.1. Nothing special, it ever worked till ios 8.0 said hello. The function sendMail sends a mail when a button gets tapped (set via storyboard). I debugged it and the code seems ok, but it crashes with a EXC_BAD_ACCESS code=1 error whenever you're supposed to return back to the main app, like when you tap the send or dismiss button of the MFMailComposeViewController. It seems to me that my View, i mean the view calling the MFMailComposeViewController is deallocated when the MFMailComposeViewController is called, so that when it get dismissed, there's nothing to return on. Some ideas to solve the problem? [The function didFinishWithResult is never reached: the crash happens before.]

EDIT: To be precise it crashes with bad_access if in the presentViewController i set animated to NO. If it is YES it complain about 'unbalanced calls to begin/end appearance transitions' and tapping send/dismiss does nothing (it not returns. The mail view is alive but tap button does nothing)

EDIT: I am right about the deallocation. He have the same problem but it does not seems to have a valid solution MFMailComposeViewController crash in iOS6 ARC In my case Arc is turned off and i cannot turn it on for various reasons. The theory is confirmed by zombie instrument. It says 'An Objective-C message was sent to a deallocated 'View' object (zombie) at address: 0x14e01720'

View.h
included MFMailComposeViewControllerDelegate and imported
#import <MessageUI/MFMailComposeViewController.h>

View.m
-(IBAction)sendEmail:(id)sender{

NSString *mailDiretta=emailText.currentTitle;

composer = [[MFMailComposeViewController alloc] init];
[composer setMailComposeDelegate:self];
if ([MFMailComposeViewController canSendMail]) {
    [composer setToRecipients:[NSArray arrayWithObjects:mailDiretta, nil]];
    [composer setSubject:@"Infos"];
    [composer setMessageBody:@"Write to me, dude!" isHTML:NO];
    [composer setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
    [self presentViewController:composer animated:YES completion:NULL];
    [composer release];
} else
[composer release];
}

// function below is never reached
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
if (error) {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"error"
                                                    message:[NSString stringWithFormat:@"error %@", [error description]]
                                                   delegate:nil cancelButtonTitle:@"dismiss" otherButtonTitles:nil, nil];
    [alert show];
    [self dismissViewControllerAnimated:YES completion:NULL];
} else {
    [self dismissViewControllerAnimated:YES completion:NULL];
}
}

Upvotes: 0

Views: 367

Answers (1)

Mark McCorkle
Mark McCorkle

Reputation: 9414

I would assume it's because you're releasing the composer before it finishes.

[composer release];

EDIT: How is this property initialized and why is it a property? Create it in the method and try. Also, your unbalanced calls are happening because you're animating a UIAlert at the same time you are animating the mail controller dismiss. Each needs to finish prior to prevent that message.

composer = [[MFMailComposeViewController alloc] init];

Try to remove the property and initialize in the function.

MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];

Make sure you added the delegate properly as well.

#import <MessageUI/MessageUI.h>
@interface YourViewController : UIViewController <MFMailComposeViewControllerDelegate> 

Set your delegate like this

composer.mailComposeDelegate = self;

For the unbalanced calls, rearrange your alert like this...

[self dismissViewControllerAnimated:YES completion:NULL];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"error"
                                                message:[NSString stringWithFormat:@"error %@", [error description]]
                                               delegate:nil cancelButtonTitle:@"dismiss" otherButtonTitles:nil, nil];
[alert show];

EDIT 2: After seeing your comment about not being able to use ARC due to one class I would advice you to simply set a -fno-objc-arc compiler flag on that class and enable ARC across your project and make your life WAY easier. Disable Automatic Reference Counting for Some Files

Upvotes: 1

Related Questions