14

I've seen several questions before such as this but for the lack of an accepted answer as well as having implemented everything as needed I still continue to face the issue as follows: I display the mail composer but on clicking cancel, the composer view freezes. I think this is due to the Save/Delete draft action sheet showing up out of the visible frame. Yes I have set the mailComposeDelegate to the presenting view controller and have read up on several similar questions where user's have not handled the (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error delegate to dismiss the composer on cancel. I have handled that as well but I cant seem to figure out for the life of me why the action sheet wont show up in the visible area of the screen in the iPhone version of my universal app. The view frame of the viewcontroller modally presenting the mail composer as NSLogged is (0,0,320,480). My app is universal & the mail composer works perfectly on the iPad. Below is a screenshot of how the composer view looks, running on iPhone Simulator 5.1:-

enter image description here
Here's the code to display the composer:

-(IBAction)mailButtonPressed:(id)sender {

    MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
    controller.mailComposeDelegate = self;
    [controller setSubject:@"Subject"];
    [controller setMessageBody:@"Test" isHTML:YES];
    [controller setToRecipients:nil];

    if(controller) {
        [self presentModalViewController:controller animated:YES];
        [controller release];
    }
}

- (void)mailComposeController:(MFMailComposeViewController*)controller 
          didFinishWithResult:(MFMailComposeResult)result
                        error:(NSError*)error 
{ 
    [self dismissModalViewControllerAnimated:YES];
}
Community
  • 1
  • 1
batman
  • 1,937
  • 2
  • 22
  • 41
  • can you post the code for how you are presenting the mail composer? – Eric Dec 13 '12 at 18:54
  • I've edited the question with added code – batman Dec 13 '12 at 18:57
  • Please also post code for didFinishWithResult delegate method – Atif Azad Dec 13 '12 at 19:09
  • Try printing out the error: NSLog(@"Error: %@", error); – Eric Dec 13 '12 at 19:14
  • The delegate does not get triggered for that to be done! Presumably because of the Save/Discard draft action sheet that normally shows up. – batman Dec 13 '12 at 19:15
  • Ok try commenting out the controller release line.. want to see if maybe its getting dealloced before dismissing – Eric Dec 13 '12 at 19:18
  • I did try that but to no avail :( – batman Dec 13 '12 at 19:19
  • Very weird.. I am guessing it has something to do with you having a universal app and having something wrong in your setup... But I just can't really know much else without diving in to your project.I would try to maybe do the same approach somewhere else in your app or in a new app altogether to see if you can get different results – Eric Dec 13 '12 at 19:27
  • I did try with a different view. The one presenting the mail composer is one of several views. Trying to display the mail composer in other views works correctly. I tried deleting and recreating the 'issue' view controller but had no change in results. – batman Dec 13 '12 at 19:32
  • the view controller handling the mailButtonPressed method, is it inside a navigation controller? – Nitin Alabur Dec 13 '12 at 19:47
  • Wow... You counter my moves every time! I am pretty stumped now.. Is there anything different about the problem view controller than the other ones. Things like: Is the problem vc presented modally when the others aren't, Is it part of a navigation stack and the others aren't. Something has to be different with that vc then the others – Eric Dec 13 '12 at 19:48
  • @calvinBhai : No its only a view controller. – batman Dec 13 '12 at 19:52
  • @Eric: I know i do. Cuz i've fought tooth and nail with this issue and seem to be losing having tried almost everything possible! I've even gone to the extent of replacing the contents of other views with the problem one with the exception of adding the mail composer code and still nothing solves! – batman Dec 13 '12 at 19:53
  • does your viewcontroller conform to MFMailComposeViewControllerDelegate? – Nitin Alabur Dec 13 '12 at 20:20
  • Yeah it does conform. Basically, i've setup the mail composer in what would be considered the 'ideal' way to say the least. – batman Dec 13 '12 at 20:35
  • 2
    Trigger the problem, then pause in the debugger. Run this debugger command: `po [[UIApp keyWindow] recursiveDescription]`. Copy the output and paste it into your question. – rob mayoff Dec 23 '12 at 07:16
  • I tried this on iOS5.1 and on iOS 6.0. I have not been able to get the delegate to execute no matter what I try, whether or not the "discard draft" message ever appears. It's as though the documentation for the delegate method is wrong. I don't think the problem is the "discard draft" being offscreen, I think it's the delegate not being called. – emrys57 Dec 23 '12 at 15:44
  • @robmayoff the problem is the debugger doesnt pause ever :( – batman Dec 23 '12 at 16:29
  • @emrys57 the only reasonable explaination i find for the view the UI looks is the action sheet coming up but not being visible. Can you shed light on ur scenario to get the same problem ? :( – batman Dec 23 '12 at 16:30
  • I agree your version looks like the action sheet appearing offscreen. However, I don't see that dimming on either iPhone (3GS or 4) I tried it on. I do see the "discard draft" action sheet when there is an unsent, edited draft to be discarded. But the delegate is never called. ` MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc]init]; mailer.delegate = self; [self presentModalViewController:mailer animated:true];` – emrys57 Dec 23 '12 at 17:16
  • You were right to be suspicious. I wrote `mailer.delegate = self;` instead of `mailer.mailComposeDelegate = self;` and did indeed have the wrong delegate definition. Now the code behaves perfectly normally on both these iPhones. No dimmed views; everything dismisses as expected. I started trying with an iPhone app, and that was normal. I switched it to a universal app running on iPhones, and that was normal too. – emrys57 Dec 23 '12 at 22:27
  • I think there's something wrong with the UIWindow. how do you set it up? You should create it in `application:didFinishLaunchingWithOptions:` with `self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];` – Felix Dec 24 '12 at 14:21
  • thats precisely the same way its setup. an nslog of the frame prints {{0, 0}, {320, 480}} – batman Dec 24 '12 at 17:19
  • OK, none of us has any idea, and I tried to reproduce it and failed miserably. How about sharing the entire xcode project and letting us run it and see if we get the same result? Github? And, by the way, Happy Christmas! – emrys57 Dec 24 '12 at 20:33
  • can you paste code of didFinishLaunchingWithOptions function of AppDelegate class.. – P.J Dec 26 '12 at 05:46
  • 1
    I have one trick, instead of [self presentModalViewController:controller animated:YES];, use rootviewcontroller class of appDelegate, by making instance of your AppDelegate [[UIApplication sharedApplication] delegate], in your current class and then just replacing self with appDelegate.(your rootviewController class). Let me know if this solves your issue. – P.J Dec 26 '12 at 05:49
  • Why doesn't your debugger pause? You should be able to run Product->Debug->Pause (or click pause button on the debugger bar) before/after clicking Cancel button and run the code rob mayoff mentioned. It can help you find out if there are any views outside of the screen. – murat Dec 26 '12 at 08:26
  • Did you make category to override `UIActionSheet` method? Is there any chance your code thinks the device is iPad and try to pop the action sheet even when it is an iPhone? – Warif Akhand Rishi Dec 27 '12 at 10:05
  • AFAIK, on the iPad the actionsheet comes up as a 'popover' and not an action sheet. – batman Dec 27 '12 at 10:06
  • @Kevin did you find the solution? I am facing the same problem. – user-123 Jun 30 '13 at 08:51
  • @AnatolyAnatoly I had this pur aside for a while before I revisited it. Ended up displaying the mail composer via the rootviewcontroller rather than the current view controller. HTH. – batman Jul 01 '13 at 10:57

6 Answers6

5

Why not try removing the code, and retrying while following a tutorial online such as this one:

http://iphonedevsdk.com/forum/tutorial-discussion/43633-quick-tutorial-on-how-to-add-mfmailcomposeviewcontroller.html

In cases like these, you always forget the one simple line of code needed to work so following a tutorial helps me make sure all the code necessary is there.

Try this code instead:

- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
    switch (result)
    {
        case MFMailComposeResultCancelled:
            NSLog(@"Mail cancelled");
            break;
        case MFMailComposeResultSaved:
            NSLog(@"Mail saved");
            break;
        case MFMailComposeResultSent:
            NSLog(@"Mail sent");
            break;
        case MFMailComposeResultFailed:
            NSLog(@"Mail sent failure: %@", [error localizedDescription]);
            break;
        default:
            break;
    }

    // Close the Mail Interface
    [self dismissViewControllerAnimated:YES completion:NULL];
}
Yo_Its_Az
  • 2,043
  • 2
  • 18
  • 25
2

Use this whole code here for the message:

.h

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

.m

  -(IBAction)Email {

        MFMailComposeViewController *composer = [[MFMailComposeViewController alloc] init];
            [composer setMailComposeDelegate:self];
            if ([MFMailComposeViewController canSendMail]) {
                [composer setToRecipients:[NSArray arrayWithObjects:@"contact_aaron@easy.com", nil]];
                [composer setSubject:@"Idea for Basic Calculator"];
                [composer setMessageBody:@"My idea is:" isHTML:NO];
                [composer setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
                [self presentModalViewController:composer animated:YES];

    }

-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
    if (error) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error with message" message:[NSString stringWithFormat:@"Error %@", [error description]] delegate:nil cancelButtonTitle:@"Try Again Later!" otherButtonTitles:nil, nil];
        [alert show];
        [self dismissModalViewControllerAnimated:YES];
    }
    else {
        [self dismissModalViewControllerAnimated:YES];
    }
}
OnkaPlonka
  • 1,232
  • 10
  • 19
  • thanks, but the problem in essence isn't the code because as i've mentioned in the string of comments to my question, the code posted in the question works perfectly in other views. – batman Dec 28 '12 at 17:18
2

It is possible that the device you are trying is not able to send mail for some reason

You can check this with [MFMailComposeViewController canSendMail]

Ismael
  • 3,927
  • 3
  • 15
  • 23
0

Apply this in

-(void)displayComposerSheet

if(composer != nil) {

    [composer release];

    composer = nil;

}

After giving value to this object

[picker composer];
Dinesh Raja
  • 8,501
  • 5
  • 42
  • 81
Vishal
  • 556
  • 4
  • 18
0

Looks like you are not using Automatic Reference counting (ARC). You are releasing the mail compose controller too early. Release it after it's dismissed.

Remove this line: [controller release]

if(controller) {
    [self presentModalViewController:controller animated:YES];
    /// remove this: ---->  [controller release];
}

and release this controller here

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

    [controller release]; // <----     add this
}
Alex L
  • 8,419
  • 6
  • 43
  • 51
0

Add this to your (all) UIViewControllers to check whether your iPhone runs out or memory. That could explain the weird behaviour i.e. mailComposerSheet released your base viewController, so the mailComposerDelegate is nil.

- (void)didReceiveMemoryWarning
{
  NSLog(@"didReceiveMemoryWarning");
  [super didReceiveMemoryWarning];
}
JOM
  • 8,139
  • 6
  • 78
  • 111