MFMailComposeViewController Crashes because of Global Appearance Properties on iOS6
Asked Answered
M

3

10

I am getting the following crash when I present a MFMailComposeViewController:

2013-11-08 11:04:05.963 <redacted>[7108:1603] *** Assertion failure in NSDictionary *_UIRecordArgumentOfInvocationAtIndex(NSInvocation *, NSUInteger, BOOL)(), /SourceCache/UIKit/UIKit-2380.17/UIAppearance.m:1118
2013-11-08 11:04:06.032 <redacted>[7108:1603] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unknown key, "NSColor" in title text attributes dictionary'

I've tracked it down to the following appearance setting in my AppDelegate's application:didFinishLaunchingWithOptions: method:

        [[UINavigationBar appearance] setTitleTextAttributes:
            @{NSForegroundColorAttributeName : [UIColor whiteColor]}];

Commenting that line out does the trick, but ruins the rest of the app, so I tried specifically setting the titleTextAttributes to an empty dictionary for the MFMailComposeViewController:

Attempt #1

        [[UINavigationBar appearanceWhenContainedIn:
            NSClassFromString(@"MFMailComposeViewController"), nil]
            setTitleTextAttributes:@{ }];

That results in the same crash. And

        [[UINavigationBar appearanceWhenContainedIn:
            NSClassFromString(@"MFMailComposeViewController"), nil]
            setTitleTextAttributes:nil];

also results in the same crash.

Attempt #2

I noticed that MFMailComposeViewController is a UINavigationController, so maybe the global appearance settings are localized to UIViewControllers inside a UINavigationController. I put together some code to figure out what view controllers are inside the MFMailComposeViewController:

        for (UIViewController *viewController in mailViewController.viewControllers) {
            NSLog(@"%@", NSStringFromClass([viewController class]));
        }

Which results in the output:

2013-11-08 11:04:05.936 <redacted>[7108:907] MFMailComposeInternalViewController

So I tried (even though it's bad practice to rely on Apple's private view controllers):

        [[UINavigationBar appearanceWhenContainedIn:
            NSClassFromString(@"MFMailComposeViewController"), nil]
            setTitleTextAttributes:@{ }];

And

        [[UINavigationBar appearanceWhenContainedIn:
            NSClassFromString(@"MFMailComposeViewController"), nil]
            setTitleTextAttributes:nil];

But that still results in the same crash!

Attempt #3

        // right before instantiating the MFMailComposeViewController
        [[UINavigationBar appearance] setTitleTextAttributes:@{ }];

And

        [[UINavigationBar appearance] setTitleTextAttributes:nil];

Then restoring the global appearance properties in the completion block of dismissViewController:animated:completion:

However, this approach didn't work either. Does anyone know how to set titleTextAttributes on the global UINavigationBar appearance without crashing MFMailComposeViewController?

Mannerism answered 8/11, 2013 at 16:28 Comment(0)
W
21

Try using UITextAttributeTextColor instead of NSForegroundColorAttributeName.

Watkins answered 8/11, 2013 at 19:52 Comment(6)
Man, I can't believe it was something this dumb. This is one of those enums that keeps going back and forth through the iOS releases; I can't keep it straight in my head.Mannerism
Oh dear Lord, thank you Jonathan!! 20 person-hours of debugging solved with this.Spindlelegs
I'd like to add that the same problem appears with QLPreviewController. It crashes when using UIAppearance and NSForegroundColorAttributeName. Using the now deprecated UITextAttributeTextColor works fine.Insolence
my problem seemed to be a combination of this and changing NSFontAttributeName to UITextAttributeFont as wellHootchykootchy
It seems iOS 8 bug, but no luck even with the above solution.Wivinia
The compiler will not allow this in iOS8.Nudibranch
G
2

Just extends UINavigationController class

@interface MyNavigationController : UINavigationController
@end

replace all your UINavigationController class with the new subclass and [appearanceWhenContainedIn:] in your app delegate

[UINavigationBar appearanceWhenContainedIn:[MyNavigationController class], nil].titleTextAttributes = @{ NSForegroundColorAttributeName : [UIColor whiteColor] };

after that your app will not crash.

Groundnut answered 15/1, 2014 at 6:5 Comment(1)
I prefer this solution since it is more architecturally correct.Gasparo
M
0

The only way I was able to solve this was to create [[UINavigationBar appearanceWhenContainedIn:] setTitleTextAttributes:] for each of my UIViewControllers. Luckily this was fairly simple, because all of my custom view controllers come from 4 view controller subclasses.

Edit: see this answer because I'm dumb.

Mannerism answered 8/11, 2013 at 19:38 Comment(1)
did you file a bug with apple?Detinue

© 2022 - 2024 — McMap. All rights reserved.