Why is MFMailComposeViewController returning MFMai

2019-07-04 09:31发布

I'm facing a strange issue in my app and I need your help !
I am using a MFMailComposeViewController to send emails with attachment data. The attachment is either a PDF, a CSV or a XLS file. A ZIP file can also be added to the mail.

Everything works fine in most cases but sometimes (actually quite often), when the attachment is a XLS and a ZIP is added, I receive multiple memory warnings and the composer returns MFMailComposeResultFailed, with an error that doesn't help at all (only saying code error 1, "The operation couldn’t be completed. (MFMailComposeErrorDomain error 1.)").

My question is why does it do that ? I assume the memory warnings are telling me something is not well managed but I can't figure out what...

Here is my code for sending the email

-(void) sendMail {

    MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init]; 
    [self prepareMailPicker:picker];

    NSString *filePath = [self getFilePath:pType];

    NSString *zipFile = [self getZipPath];

    NSString *mimeType;
    int userPhoto = [User getCSVPhoto];

    switch (pType) {
        case EPDF:
            mimeType = @"application/pdf";
            userPhoto = [User getPDFPhoto];
            break;
        case ECSV:
            mimeType = @"text/csv";
            break;
        case EExcel:
            mimeType = @"application/vnd.ms-excel";
            break;

        default:
            break;
    }

    NSData *attachmentData = [NSData dataWithContentsOfFile:filePath];
    [picker addAttachmentData:attachmentData mimeType:mimeType fileName:[filePath lastPathComponent]];

    if (userPhoto == 1 && shouldAddZip) {
        NSData *zipData = [NSData dataWithContentsOfFile:zipFile];
        [picker addAttachmentData:zipData mimeType:@"application/zip" fileName:[zipFile lastPathComponent]];
    }

    shouldAddZip = NO;

    [self presentModalViewController:picker animated:YES];
}

-(void) prepareMailPicker:(MFMailComposeViewController*)picker {

    picker.mailComposeDelegate = (id<MFMailComposeViewControllerDelegate>)self;

    picker.navigationBar.tintColor = grayDark;

    [picker setSubject:[TextManager textForKey:@"EMAIL_SUBJECT"]];

    NSString *email = [[User currentUser] getEmail];

    if (email && ![email isEqualToString:@""])
        [picker setToRecipients:[NSArray arrayWithObject:email]];

    NSString *emailBody = [TextManager textForKey:@"EMAIL_TEXT"];
    [picker setMessageBody:emailBody isHTML:YES];
}

Any help would be grately apreciated !

EDIT: as asked by @matt, here is a log to prove that nothing is set to nil :

filePath : /var/mobile/Applications/A57F5CD2-E3FE-4417-8810-D746A22CF434/Documents/iNdF_Export_2012-11-19.xls
zipFile : /var/mobile/Applications/A57F5CD2-E3FE-4417-8810-D746A22CF434/Documents/iNdF_recus_2012-11-19.zip
attachmentData : (NSConcreteData *) <0x1d9c3c20> 53 874 bytes
zipData : (NSConcreteData *) <0x1f989100> 6 838 456 bytes

3条回答
手持菜刀,她持情操
2楼-- · 2019-07-04 09:37

I guess that the problem is related to memory, when you create NSData you create in the heap. If it is to big you'll start to receive memory warnings. One way to avoid memory could be create a memory mapped NSData or an an NSStream but I have no idea on how to integrate a NSStream in mail composer. Which is the average size of your attachment?
You can also try to profile your app with Allocations to see wich is the memory footprint of your app, maybe is already too high.

查看更多
再贱就再见
3楼-- · 2019-07-04 09:47

like the some problems i had faced before. 1. Please check, there is internet availability using "Reachability" class file. 2. Please check your data size is within the limit. 3. Please check you configured your email id with your device. you can also call [yourobj cansendmail] function to check whether it can send mail or not.

查看更多
小情绪 Triste *
4楼-- · 2019-07-04 09:58

as you say, the problem seems most probably to do with memory management, given the memory warnings you are receiving.

your code is retaining a reference count to the attachmentData from the first file even as it goes out to get the zipData for the second file. internally, the picker is probably copying that data …

so the more you can do to release your references to large data as early as possible, the more likely you are not to get the memory warnings.

and if the problem is that the picker is unable to finish the attachment due to running out of memory, and you are able to get through it by doing early release, then breaking up the code in the following way may help you.

- (void)sendMailPicker:(MFMailComposeViewController*)picker addAttachmentUsingMimeType:(NSString*)mimeType {
    NSString *filePath = [self getFilePath:pType];
    NSData *attachmentData = [NSData dataWithContentsOfFile:filePath];
    [picker addAttachmentData:attachmentData mimeType:mimeType fileName:[filePath lastPathComponent]];
}

- (void)sendMailAddPhotoUsingPicker:(MFMailComposeViewController*)picker {
    NSString *zipFile = [self getZipPath];
    NSData *zipData = [NSData dataWithContentsOfFile:zipFile];
    [picker addAttachmentData:zipData mimeType:@"application/zip" fileName:[zipFile lastPathComponent]];
}

- (void)sendMail {

    MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init]; 
    [self prepareMailPicker:picker];

    NSString *mimeType;
    int userPhoto = [User getCSVPhoto];

    switch (pType) {
        case EPDF:
            mimeType = @"application/pdf";
            userPhoto = [User getPDFPhoto];
            break;
        case ECSV:
            mimeType = @"text/csv";
            break;
        case EExcel:
            mimeType = @"application/vnd.ms-excel";
            break;

        default:
            break;
    }

    [self sendMailPicker:picker addAttachmentUsingMimeType:mimeType];
    if (userPhoto == 1 && shouldAddZip) {
        [self sendMailAddPhotoUsingPicker:picker];
    }

    shouldAddZip = NO;

    [self presentModalViewController:picker animated:YES];
}
查看更多
登录 后发表回答