问题
I am using MFMailComposeViewController in my conde to provide Mail functionality but after sending mail or when i want to cancel mail it will be crashing.
below is my code:
(IBAction)FnForPlutoSupportEmailButtonPressed:(id)sender {
{
if ([MFMailComposeViewController canSendMail])
{
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:@"Need help from Pluto support team"];
NSArray *toRecipients = [NSArray arrayWithObjects:@"support@myplu.to",nil];
[mailer setToRecipients:toRecipients];
NSString *emailBody = @"";
[mailer setMessageBody:emailBody isHTML:NO];
//mailer.modalPresentationStyle = UIModalPresentationPageSheet;
[self presentModalViewController:mailer animated:YES];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failure"
message:@"Your device doesn't support the composer sheet"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[alert show];
}
} }
(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
// Notifies users about errors associated with the interface
switch (result)
{ case MFMailComposeResultCancelled:
break;
case MFMailComposeResultSaved:
break;
case MFMailComposeResultSent:
break;
case MFMailComposeResultFailed:
break;
default:
break;
}
[self dismissModalViewControllerAnimated:YES];
}
I have read all blog post but no solution is found, This blog post is having good explaination about this but as per this i am not presenting my view controller in viewdidload or viewdidappear.
I'm Getting EXE_BAD_ACCESS, Following is the crash log :
**
> #0 0x00000000 in ?? ()
> #1 0x01dc5aa4 in -[UIViewController _setViewAppearState:isAnimating:] ()
> #2 0x01dc5f47 in -[UIViewController __viewDidDisappear:] ()
> #3 0x01dc6039 in -[UIViewController _endAppearanceTransition:] ()
> #4 0x01dd2e7e in -[UIViewController(UIContainerViewControllerProtectedMethods) endAppearanceTransition] ()
> #5 0x01fc8de1 in -[UIWindowController transitionViewDidComplete:fromView:toView:] ()
> #6 0x01da334b in -[UITransitionView notifyDidCompleteTransition:] ()
> #7 0x01da3070 in -[UITransitionView _didCompleteTransition:] ()
> #8 0x01da531b in -[UITransitionView _transitionDidStop:finished:] ()
> #9 0x01d23fb6 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
> #10 0x01d24154 in -[UIViewAnimationState animationDidStop:finished:] ()
> #11 0x0163bbce in CA::Layer::run_animation_callbacks ()
> #12 0x03664fe4 in _dispatch_client_callout ()
> #13 0x03655997 in _dispatch_main_queue_callback_4CF ()
> #14 0x012c03b5 in __CFRunLoopRun ()
> #15 0x012bf804 in CFRunLoopRunSpecific ()
> #16 0x012bf6db in CFRunLoopRunInMode ()
> #17 0x030f1913 in GSEventRunModal ()
> #18 0x030f1798 in GSEventRun ()
> #19 0x01ce82c1 in UIApplicationMain ()
**
As per updated document of apple for ios 5 they mentioned :
presentModalViewController:animated:
Presents a modal view managed by the given view controller to the user. (Deprecated. Use presentViewController:animated:completion:
instead.)
- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated
Parameters
Dismisses the view controller that was presented by the receiver. (Deprecated. Use dismissViewControllerAnimated:completion:
instead.)
- (void)dismissModalViewControllerAnimated:(BOOL)animated
I had tried this also but it still crashes
回答1:
You need to keep a strong reference to MFMailComposeViewController *mailer in your class, and after you dismiss it you can null that reference. Ask me how I know this :-)
@implememtation MyClass
{
MFMailComposeViewController *mailer;
}
...
(IBAction)FnForPlutoSupportEmailButtonPressed:(id)sender {
{
if ([MFMailComposeViewController canSendMail])
{
/* USE IVAR */mailer = [[MFMailComposeViewController alloc] init];
Later on, when completely done with it, you simply "mailer = nil;" to release it.
EDIT: What I do and suggest is to use a block to the main queue to do the release. If you just use 'self.mailer = nil' then the release happens after the final delegate method has finished and you are for sure no longer using it.
EDIT2: This crash does not happen all the time on all devices - I would say its somewhat of a race condition between when you receive the final delegate method and when its finished its work. Apple does not say anything about holding a reference one way or the other - however, general practice on Apple products is to assume any object you get is "on loan" through one runLoop, and thereafter if you want to keep a reference you have to retain the object.
回答2:
If your are having sharekit framework implemented in your code goto SHK.m and change
[[currentView parentViewController] dismissModalViewControllerAnimated:YES];
to
[currentView dismissModalViewControllerAnimated:YES];
This will solve your problem.
Thanks everyone for response.
and also comment these lines
SHKSwizzle([MFMailComposeViewController class], @selector(viewDidDisappear:), @selector(SHKviewDidDisappear:));
if (NSClassFromString(@"MFMessageComposeViewController") != nil) SHKSwizzle([MFMessageComposeViewController class], @selector(viewDidDisappear:), @selector(SHKviewDidDisappear:));
回答3:
HI you can use following code to send mail mail app will not send any email form simulator you have to install you application on device. EXE_BAD_ACCESS comes when you try to access the object they are not in memory and remamber device is case sensitive.
-(void)sendMail:(id)sender
{
//create instance of class at runtime.
Class mailComposer = (NSClassFromString(@"MFMailComposeViewController"));
if (mailClass != nil)
{
// check the current device is configured for sending emails
//if it is not configured for mail you open mail application on device.
if ([mailClass canSendMail])
{
[self displayComposerSheet];
}
else
{
[self launchMailAppOnDevice];
}
}
else
{
[self launchMailAppOnDevice];
}
}
-(void)displayComposerSheet
{
MFMailComposeViewController *mailPicker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:@"Welcome!"];
//recipients
NSArray *to = [NSArray arrayWithObject:@"jhon@example.com"];
[picker setToRecipients:toRecipients];
// Attach an image
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Default" ofType:@"png"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
[picker addAttachmentData:myData mimeType:@"image/png" fileName:@"Default"];
// Set email body text
//NSString *emailBody = @"......!";
//[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult: (MFMailComposeResult)result error:(NSError*)error
{
message.hidden = NO;
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
message.text = @"Canceled";
break;
case MFMailComposeResultSaved:
message.text = @"Saved";
break;
case MFMailComposeResultSent:
message.text = @"Sent";
break;
case MFMailComposeResultFailed:
message.text = @"Failed";
break;
default:
message.text = @"Not sent";
break;
}
[self dismissModalViewControllerAnimated:YES];
}
-(void)launchMailAppOnDevice
{
NSString *recipients = @"";
NSString *body = @"";
NSString *email1 = [NSString stringWithFormat:@"%@%@", recipients, body];
email1 = [email1 stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:email1]];
}
回答4:
Since the stop of the stack is 0x00000000
, I'm assuming some code inside UIKit is jumping to a nil function pointer. Enable Zombies and see if you get a zombie object access error. (Edit your project scheme, under Run/Debug, Diagnostics tab, check "Enable Zombie Objects")
回答5:
try this code, this works well without crashing.. contact us method is button target selector..
-(void)ContactUs:(UIButton*)button
{
Class mailClass = (NSClassFromString(@"MFMailComposeViewController"));
if (mailClass != nil)
{
// We must always check whether the current device is configured for sending emails
if ([mailClass canSendMail])
{
[self displayComposerSheet];
}
else
{
[self launchMailAppOnDevice];
}
}
else
{
[self launchMailAppOnDevice];
}
}
-(void)displayComposerSheet
{
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
//[picker setSubject:@"Hello from California!"];
// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:@"info@imp.co.in"];
//NSArray *ccRecipients = [NSArray arrayWithObjects:@"second@example.com", @"third@example.com", nil];
//NSArray *bccRecipients = [NSArray arrayWithObject:@"fourth@example.com"];
[picker setToRecipients:toRecipients];
//[picker setCcRecipients:ccRecipients];
//[picker setBccRecipients:bccRecipients];
// Attach an image to the email
/*NSString *path = [[NSBundle mainBundle] pathForResource:@"rainy" ofType:@"png"];
NSData *myData = [NSData dataWithContentsOfFile:path];
[picker addAttachmentData:myData mimeType:@"image/png" fileName:@"rainy"];*/
// Fill out the email body text
//NSString *emailBody = @"It is raining in sunny California!";
//[picker setMessageBody:emailBody isHTML:NO];
[self presentModalViewController:picker animated:YES];
[picker release];
}
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
message.hidden = NO;
// Notifies users about errors associated with the interface
switch (result)
{
case MFMailComposeResultCancelled:
message.text = @"Canceled";
break;
case MFMailComposeResultSaved:
message.text = @"Saved";
break;
case MFMailComposeResultSent:
message.text = @"Sent";
break;
case MFMailComposeResultFailed:
message.text = @"Failed";
break;
default:
message.text = @"Not sent";
break;
}
[self dismissModalViewControllerAnimated:YES];
}
-(void)launchMailAppOnDevice
{
NSString *recipients = @"";
NSString *body = @"";
NSString *email1 = [NSString stringWithFormat:@"%@%@", recipients, body];
email1 = [email1 stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:email1]];
}
回答6:
If you are using ARC, the controller object will have been released before you call dismiss.
Retain the object somewhere besides a stack allocated variable.
回答7:
Have you set delegate MFMailComposeViewControllerDelegate in .h file. I have faced such problem in past. And error was very minor. Please check delegate in .h file.
来源:https://stackoverflow.com/questions/11735066/mfmailcomposeviewcontroller-crashing-while-dismissmodalviewcontrolleranimated-in