开发者

Crash when using MFMailComposeViewController with UIActionSheet

I'm using the MFMailComposeViewController to send mail from within an application. I have added the code from the Apple example to a UITableViewController, and all works as expected when I trigger the modalViewController from a UIToolBarButton. The problem comes when I put a UIActionSheet between the UIToolBarButton and the MFMailComposeViewController code.

I want to present the user with the option to send by email or post to Facebook. When I call the MFMailComposeViewController methods after the dismissal of the UIActionSheet, my app crashes when the method tries to load the modalViewController. Code below, any ideas?

// UIToolBarButton generates the email string and displays the UIActionSheet with email options
- (void)onEmailButtonTouch
{
    int mySection;
    int myRow;
    emailString = [NSString stringWithFormat:@"<b><p>Ten Essentials Check List</b><br />%@</p>", [myList valueForKey:@"listName"]];

    for (mySection = 0; mySection < [[fetchedResultsController sections] count]; mySection ++)
    {
        NSString *sectionName = [NSString stringWithFormat:@"<p><b>%@ Group</b></p><ul>", [[[fetchedResultsController sections] objectAtIndex:mySection] name]];
        emailString = [emailString stringByAppendingString:sectionName];
        id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:mySection];

        for (myRow = 0; myRow < [sectionInfo numberOfObjects]; myRow ++)
        {
            // Get the managedObject
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:myRow inSection:mySection];
            NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];

            //Get the related Item object
            Item *item  = [managedObject valueForKey:@"item"];
            NSString *itemName = [NSString stringWithFormat:@"<li>%@</li>", item.itemName];
            emailString = [emailString stringByAppendingString:itemName];
        }

        emailString = [emailString stringByAppendingString:@"</ul>"];
    }

    NSLog(@"email string = :\n%@", emailString);
    [self showEmailOptions];
}

// Display an UIActionSheet with email/facebook buttons
-(void)showEmailOptions
{
    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"eMail Options" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:NULL otherButtonTitles:@"Send List via Email", @"Post List to Facebook", NULL];
    [actionSheet showFromToolbar:self.navigationController.toolbar];
    [actionSheet release];
}

// Call the MFMailComposeViewController method开发者_开发问答s if the user selects the Email button of the actioSheet
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 0)
    {
        NSLog(@"Opening email");
        [self showPicker];
    }
}


-(void)showPicker
{
    // This sample can run on devices running iPhone OS 2.0 or later  
    // The MFMailComposeViewController class is only available in iPhone OS 3.0 or later. 
    // So, we must verify the existence of the above class and provide a workaround for devices running 
    // earlier versions of the iPhone OS. 
    // We display an email composition interface if MFMailComposeViewController exists and the device can send emails.
    // We launch the Mail application on the device, otherwise.

    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];
    }
}


// Displays an email composition interface inside the application. Populates all the Mail fields. 
-(void)displayComposerSheet
{
    MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
    picker.mailComposeDelegate = self;
    [picker setSubject:@"Here is your gear check list!"];

    // Attach an image to the email
    NSString *path = [[NSBundle mainBundle] pathForResource:@"Checkmark_icon" ofType:@"png"];
    NSData *myData = [NSData dataWithContentsOfFile:path];
    [picker addAttachmentData:myData mimeType:@"image/png" fileName:@"Checkmark_icon"];

    // Fill out the email body text
    NSString *emailBody = emailString;
    [picker setMessageBody:emailBody isHTML:YES];

    // CRASH HAPPENS ON THE LINE BELOW //
    [self presentModalViewController:picker animated:YES];
    [picker release];
}


// Dismisses the email composition interface when users tap Cancel or Send. Proceeds to update the message field with the result of the operation.
- (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:
            NSLog (@"Result: canceled");
            break;
        case MFMailComposeResultSaved:
            NSLog (@"Result: saved");
            break;
        case MFMailComposeResultSent:
            NSLog (@"Result: sent");
            break;
        case MFMailComposeResultFailed:
            NSLog (@"Result: failed");
            break;
        default:
            NSLog (@"Result: not sent");
            break;
    }

    [self dismissModalViewControllerAnimated:YES];
}


#pragma mark -
#pragma mark Workaround
// Launches the Mail application on the device.
-(void)launchMailAppOnDevice
{
    NSString *recipients = @"mailto:first@example.com?cc=second@example.com,third@example.com&subject=Here is your gear check list!";
    NSString *body = emailString;
    NSString *email = [NSString stringWithFormat:@"%@%@", recipients, body];
    email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:email]];
}


I think your problem is that you need

[emailString retain];

it's an autorelease object, and I think it's getting freed after onEmailButtonTouch returns, so that it's invalid when your alert notification fires.


Actualy, David (above comment) put me on the right track. The UIActionSheet was causing my emailString ivar to become invalid, so I moved the call to the UIActionSheet to BEFORE building the emailString. Now all is working!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜