36

I've got the weirdest issue I've encountered in a long time...and I've run out of ideas.

So I've got a MFMailComposeViewController that is being launched from tapping on a UIButton and it's launching the mail composer view just fine. You see the subject I've assigned but before the to: or body fields are populated the window kind of flashes and disappears. It throws this error:

viewServiceDidTerminateWithError: Error Domain=XPCObjectsErrorDomain Code=2 "The operation couldn't be completed. (XPCObjectsErrorDomain error 2.)"

Now here's the crazy part. If I switch over to another app that also uses a MFMailComposeViewController and launch that one, then switch back to my app and launch the mail composer again, it works just fine. I can't explain that.

This only seems to be an issue on phones running iOS 6 that are not iPhone 5's.

I've searched around and can't seem to find anyone else who's experienced this same problem. Anyone got any suggestions?

I've got the MessageUI.framework linked and I also found that this wasn't working in the Simulator or on a device, but when I also linked the Security.framework it started working in the Simulator, but it still doesn't work on the devices.

My code for launching the MFMailComposeViewController is below:

in the .h file

#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMailComposeViewController.h>

in the .m file

-(void)displayComposerSheet {
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;

[picker setSubject:@"Support Request"];

// Set up recipients
NSArray *toRecipients = [NSArray arrayWithObject:@"support@domain.com"];

[picker setToRecipients:toRecipients];

// Fill out the email body text
NSString *emailBody = @"\n\nEmail from iOS";
[picker setMessageBody:emailBody isHTML:NO];

[self presentModalViewController:picker animated:YES];
}


// 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
{

    [self dismissModalViewControllerAnimated:YES];
}

Update: I think I've narrowed it down to the settings I have passed to the appearance delegate for the UINavigationBar. I have it using a custom font, and if I turn that off it seems to work...but why would that work on the iPhone5...

David H
  • 40,852
  • 12
  • 92
  • 138
gplocke
  • 701
  • 7
  • 14
  • Have the same trouble when called from UIActivityViewController... Did you find any solution? – Shmidt Oct 28 '12 at 09:08
  • Nope, but I did determine there's something else affecting it because I made a sample project that only did this and nothing else and it worked fine. But I never figured out the root of the issue. For now, I just ended up changing the font to a system font for this situation and leaving the rest. – gplocke Nov 01 '12 at 12:39
  • @gplocke post an answer your own question – codeperson Jan 07 '13 at 09:46
  • I’ve filed this as rdar://13422715 (http://www.openradar.me/13422715) – Yang Meyer Mar 14 '13 at 19:17

9 Answers9

16

Setting a custom font for the UITextAttributeFont to the titleTestAttributes of the UINavigationBar appearance proxy causes the bug as the OP and MightlyLeader identified.

Workaround Code:

// remove the custom nav bar font
NSMutableDictionary* navBarTitleAttributes = [[UINavigationBar appearance] titleTextAttributes].mutableCopy;
UIFont* navBarTitleFont = navBarTitleAttributes[UITextAttributeFont];
navBarTitleAttributes[UITextAttributeFont] = [UIFont systemFontOfSize:navBarTitleFont.pointSize];
[[UINavigationBar appearance] setTitleTextAttributes:navBarTitleAttributes];

// set up and present the MFMailComposeViewController
MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init];
mailComposer.mailComposeDelegate = self;
[mailComposer setSubject:emailInfo[@"subject"]];
[mailComposer setMessageBody:emailInfo[@"message"] isHTML:YES];
mailComposer.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:mailComposer animated:YES completion:^{

    // add the custom navbar font back
    navBarTitleAttributes[UITextAttributeFont] = navBarTitleFont;
    [[UINavigationBar appearance] setTitleTextAttributes:navBarTitleAttributes];
}];
dberwick
  • 131
  • 1
  • 5
  • The last two lines should be called after a short delay, otherwise the problem will still arise (tested on an iPhone 4). Adding the delay the problem is definitely fixed. – marzapower Feb 06 '13 at 10:55
  • You're correct. This was enough to fix this for me the first time but the bug recently reappeared. I moved it to the `mailComposeController:didFinishWithResult:error:` callback which fixed it again. I'll update the code to reflect. – dberwick Feb 15 '13 at 04:03
  • 1
    Updated it to use the completion block on the presentation call. – dberwick Mar 13 '13 at 23:22
  • 3
    It seems you don't need to actually change the font settings back and forth every time you show a mail composer. Wouldn't setting the system font once for `[UINavigationBar appearanceWhenContainedIn: [MFMailComposeViewController class], nil]` do the same trick? – Egor Chiglintsev Jul 09 '13 at 04:59
12

This problem recently popped up on a project I'm working on. I didn't really like the workaround above so instead I created the following (maybe a little cleaner) workaround:

// Implement the custom font for all UINavigationBar items
[[UINavigationBar appearance] setTitleTextAttributes:
@{
    UITextAttributeFont : [UIFont custom_superAwesomeFontWithSize:16.0f],
}];


// Disable the custom font when the NavigationBar is presented in a MFMailComposeViewController
[[UINavigationBar appearanceWhenContainedIn:[MFMailComposeViewController class], nil] setTitleTextAttributes:
 @{
    UITextAttributeFont : [UIFont boldSystemFontOfSize:14.0f],
 }];
jnjosh
  • 121
  • 1
  • 3
  • That's a clean solution. Much better than the workaround shown above. – Kof May 11 '14 at 12:41
  • I agree appearanceWhenContainedIn: is a nicer solution. There's a trade off though. a) your workaround code now lives somewhere separate from your bug. and b) your font is not actually the custom font anymore during presentation. – dberwick Dec 23 '14 at 20:33
9

I had the same issue. I had set the text attributes of the title bar to a custom font. When I removed the custom font specification (but left all the other attributes to custom values) the issue disappeared.

My diagnosis is that custom fonts take too long to load and it triggers a time-out from the wait-fences.

Cocoadelica
  • 3,006
  • 27
  • 30
3

Make this an ivar:

MFMailComposeViewController *picker 

Then after this line:

[self dismissModalViewControllerAnimated:YES];

add this:

dispatch_async(dispatch_get_main_queue(), ^{ picker = nil; });

So that the release of the picker does not happen until the next runloop cycle.

David H
  • 40,852
  • 12
  • 92
  • 138
2

This happens when we put fractional value in the custom UINavigationBar for example [[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(1.5, -1.5) forBarMetrics:UIBarMetricsDefault]; Set offset value as UIOffsetMake(1.0, -1.0) and this will work. Hope this helps.

Slashik
  • 325
  • 1
  • 4
1

dberwick's workaround kinda works - the composer no longer cancels itself automatically, and the custom navbar title font setting is restored once you close the message composer, but it does not show the custom font in the message composer itself.

I just hated how the workaround bloated my actual code, so here’s a simple way to move most of it out:

- (void)presentMessageCommposer
    void (^workaroundRestoreFont)(void) = [self ym__workaroundCustomFontInMessageComposer];

    MFMailComposeViewController *mailComposeVC = [MFMailComposeViewController new];
    // ... set up the composer: message body, subject, etc ...
    [self presentViewController:mailComposeVC animated:YES completion:workaroundRestoreFont];
}


// ugly workaround stuff
// move this to the bottom of your class, collapse it, or put it in a category
- (void (^)(void))ym__workaroundCustomFontInMessageComposer
{
    // Bug http://openradar.appspot.com/13422715
    // remove the custom nav bar font
    NSMutableDictionary* navBarTitleAttributes = [[UINavigationBar appearance] titleTextAttributes].mutableCopy;
    UIFont *navBarTitleFont = navBarTitleAttributes[UITextAttributeFont];
    navBarTitleAttributes[UITextAttributeFont] = [UIFont systemFontOfSize:navBarTitleFont.pointSize];
    [[UINavigationBar appearance] setTitleTextAttributes:navBarTitleAttributes];

    return ^{
        // add the custom navbar font back
        NSMutableDictionary* navBarTitleAttributes = [[UINavigationBar appearance] titleTextAttributes].mutableCopy;
        navBarTitleAttributes[UITextAttributeFont] = navBarTitleFont;
        [[UINavigationBar appearance] setTitleTextAttributes:navBarTitleAttributes];
    };
}

(This should really be a comment to dberwick’s answer, but that wouldn’t allow for this much code.)

Yang Meyer
  • 5,409
  • 5
  • 39
  • 51
1

I have the same issue but I think I solved it by subclassing UINavigationBar. I change the appearance of my subclass instead of UINavigationBar.

[[MYNavigationBar appearance] setTitleTextAttributes:@{
    UITextAttributeFont : [UIFont fontWithName:@"Custom Font" size:25]
}];
David Brockman
  • 567
  • 4
  • 6
0

Simply adding the composer as iVar solved the problem for me.

MFMailComposeViewController *emailComposer;

Ram E.K
  • 1
  • 1
-2

From what I've read, in iOS 6, this is deprecated:

[self presentModalViewController:picker animated:YES];

They suggest using:

[self presentViewController:picker animated:YES completion:nil];

paired with (in didFinishWithResult)

[[controller presentingViewController] dismissViewControllerAnimated:YES completion:nil];

Unfortunately, this only works intermittently on the Simulator... but it does work sometimes!

tjdecke
  • 567
  • 4
  • 11
Michael Dougan
  • 1,698
  • 1
  • 9
  • 13