27

really, really odd error

I have an app that was working fine in iOS5/.1, now I'm having a few transition problems with iOS6 but this one is confusing.

I have some code that launches a mail composer, and since iOS 6 it causes a crash with this error:

* Assertion failure in -[UICGColor encodeWithCoder:], /SourceCache/UIKit/UIKit-2372/UIColor.m:1191 2012-09-26 02:14:38.044 MyCQs Medical[2126:1b03] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Only support RGBA or the White color space, this method is a hack.'

Any suggestions? Through trial and error commenting out various lines it seems to be the alloc/init line that causes the error, though when all the lines are uncommented, all of the NSLogs are executed, including "present" which indicates that everything that should be called, has been. the app crashes before the mailcomposer is presented on screen, I'd really appreciate any advice here

            if (indexPath.row == 3) {
               if([MFMailComposeViewController canSendMail]){
                   mailComposer = [[MFMailComposeViewController alloc]init];
                   NSLog(@"Alloc, init");
                   mailComposer.mailComposeDelegate = self;
                   NSLog(@"Set delegate");
                   NSArray *toArray = [[NSArray alloc]initWithObjects:@"john@doe.com", nil];
                   NSLog(@"To array");
                   [mailComposer setToRecipients:toArray];
                   NSLog(@"To recipients");
                   [mailComposer setSubject:@"Message from a MyCQs user!"];
                   NSLog(@"Subject");
                   NSLog(@"About to present mail composer");
                   [[mailComposer navigationBar] setTintColor:[UIColor blackColor]];
                   [self presentModalViewController:mailComposer animated:YES];
                   NSLog(@"Present");
             }
    }
James Gupta
  • 871
  • 7
  • 15
  • 1
    Have you tried setting the tint coor of your mailComposer's navigationBar like this? mailComposer.navigationBar.tintColor = [UIColor colorWithRed:1.0 Green:1.0 Blue:1.0 Alpha:1.0];? – geraldWilliam Sep 26 '12 at 01:40
  • hi Gerald cheers for the reply - yes I have tried that, as I suspected it might be the fact that I've taken advantage of iOS 6's 'custom status bar tint color' (long shot I know). My app has custom graphics for navigation bars etc....not sure if that has anything to do with it – James Gupta Sep 26 '12 at 01:53
  • he assertion failure details lead me to believe that, perhaps unawares, you are attempting to archive a color that does not conform to the NSCoding protocol. Hopefully that gives you some kind of hint. I hae to run at the moment but I'll look in later and see whether you've resolved this issue and whether I can try to help. – geraldWilliam Sep 26 '12 at 02:07
  • Oh here's a thought. Try subclassing MFMailComposeViewController, presenting that and setting the navigationBar.tintColor in its viewDidLoad. – geraldWilliam Sep 26 '12 at 02:18
  • I agree it must be something to do with archiving colours...when I google that error the only times it comes up are when people are attempting to do that. However, it just seems strange that it should come up on MFMailComposeViewController alloc/init? Especially as it worked without any warnings in iOS 5.1 and I can't see any documented changes to that class. I've just tried running it after disabling all of my custom graphics in case it had something to do with that but still the same problem! – James Gupta Sep 26 '12 at 02:22
  • Got it working...for some reason when I comment out these two lines in my applicationDidFinishLaunchingWithOptions code it works: [[UIToolbar appearance] setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"navBar-bkg.png"]]]; // [[UITableView appearance]setSeparatorColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"dotted-line2.png"]]]; it works...though obviously it messes up the aesthetic of the rest of my app. I might try the subclassing route but to me its looking like I'm going to have to subclass UITableView and UIToolbar for everything else instead? – James Gupta Sep 26 '12 at 02:39
  • UPDATE: I've changed some things around with my UIToolBar appearance and now its JUST this line that causes the crash: [[UITableView appearance]setSeparatorColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"dotted-line2.png"]]]; I've subclassed MFMailComposeViewController but I don't know how to access the tableview within it? – James Gupta Sep 26 '12 at 10:23
  • What's weirder is, if I go with a standard UIColor for the separator colour, the mail composer loads but it DOESNT use the custom separator colour I've specified, so I don't know how using a colorWithPatternImage should affect it at all. I think for now I'll have to either subclass UITableView or use a solid colour if the device is running iOS 6, which is a shame because I put a lot of effort into the app's graphics :( I think maybe worth submitting this as a bug to Apple? – James Gupta Sep 26 '12 at 10:36
  • 2
    Why isn't Apple even aware of this? This is an obvious bug that they need to fix asap. – ryan Feb 07 '13 at 22:03
  • I can reproduce this bug in iOS 8. I can't believe this bug has been existing for 2 years, and Apple hadn't solved it.... – Brian Apr 07 '15 at 15:32

10 Answers10

8

Ok only a partial solution but it's the best one I can think of without some fairly disruptive code changes.

For anyone else who gets this problem in future, I think it's a bug in iOS 6, MFMailComposeViewController crashes when you have set the UITableView separatorStyle to a colorWithPatternImage, but it works fine when you use a solid colour, so:

        if ([[[UIDevice currentDevice] systemVersion] floatValue] > 5.2) {
           NSLog(@"Using iOS 5x");
           [[UITableView appearance]setSeparatorColor:[UIColor colorWithRed:142.0/255.0          green:130.0/255.0 blue:76.0/255.0 alpha:1.0]];
        }
        else {
           NSLog(@"Using iOS 6x, Table view use pattern color");
           [[UITableView appearance]setSeparatorColor:[UIColor colorWithPatternImage: [UIImage imageNamed:@"dotted-line2.png"]]];
        }
James Gupta
  • 871
  • 7
  • 15
5

Actually I believe this is a significant bug, did anybody file a radar, yet?

As it seems to me, the assertion throws whenever you use "colorWithPatternImage" ANYWHERE in your presenting view controller's appearance proxies.

I think what happens is that iOS tries to store the appearance of your App before switching to a separate service (which is what MFMailComposeViewController does, it's now a "remote view controller" that gets presented by your App but which is managed by another App/process), since the Mail App wants to determine the appearance itself so it changes things like tint colors etc. More about remote view controller here, in case somebody is interested: http://oleb.net/blog/2012/10/remote-view-controllers-in-ios-6/

This seems to fail. This has to be a bug, the image should be encodable.

Workarounds may be hard. I tried to exchange the patterned color for a plain one right before presenting the view controller but found you at least have to make sure it really gets redrawn on screen and gave up (I don't really needed the pattern).

coolio
  • 161
  • 5
5

My problem was also due to using colorWithPatternImage but I found that it seems to only cause an issue when used on elements that are shown on the MFMailCompserViewController e.g.:

[[UINavigationBar appearance] setTintColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"navbar"]]];
Imran
  • 1,488
  • 1
  • 15
  • 36
4

I've found that MFMailComposeViewController only crashes when colorWithPatternImage is used in [[UITableView appearance] statement. I've had no problem when I set the background and separatorColor in the table's viewDidLoad. The only problem is you need to do this for each table.

[self.tableView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"image.png"]]];
[self.tableView setSeparatorColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"image.png"]]];
hol
  • 8,255
  • 5
  • 33
  • 59
Steve Weyl
  • 41
  • 1
2

@coolio is right, it seems to happen when using a patterned color with any controller class. (At least UITabBarController and UITableViewController, apparently.)

I got around this by subclassing my tab bar controller and using appearanceWhenContainedIn:. That way you can still use your fancy texture with no need to subclass MFMailComposeViewController or sniff iOS versions, etc.

UIColor *tabBarBgPattern = [UIColor colorWithPatternImage:...];
[[UITabBar appearanceWhenContainedIn:[MyTabBarController class],
                                     nil]
                  setBackgroundColor:tabBarBgPattern];
taber
  • 3,166
  • 4
  • 46
  • 72
1

This thread gave me great clues on how to fix a similar problem in my App using ShareKit and attempting to email an image of a view. Now I only change the UISwitch appearance for versions less than 6.0.

This code gets called when my app starts up:

// Protect against IOS 6.0 BUG: 'NSInternalInconsistencyException', reason: 'Only support RGBA or the White color space, this method is a hack.'
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0) {
    UIImage *patternImage = [UIImage imageNamed:@"solid-colors_blue.png"];
    UIColor* switchColor = [UIColor colorWithPatternImage:patternImage];
    [[UISwitch appearance] setOnTintColor: switchColor];
}  
1

I'm facing the same issue using 'colorWithPatterImage' for a UIBarButtonItem inside the navBar of my tableViewController used to display the a modal view (I'm not using MFMailComposeViewController).

[[UIBarButtonItem appearance] setTintColor:[UIColor colorWithPatternImage:bgImage]];

I needed to replace it with a RGBa color;

link82
  • 31
  • 1
  • 4
1

My apps were crashing on iOS 7 when using colorWithPatternImage and trying to present an MFMailComposeViewController. I have to determine the color from a UIImage because the UIImage can be chosen by the user, and I want to "theme" my application based on the user's selected image.

The solution for me (albeit kind of hacky) is to grab the RGBA values of the origin (0,0) of the UIImage, then apply that as the background color instead of using colorWithPatternImage.

+ (UIColor*)getUIColorFromImageAtOrigin:(UIImage*)image
{        
    // First get the image into your data buffer
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    // Now your rawData contains the image data in the RGBA8888 pixel format.
    int byteIndex = (bytesPerRow * 0) + 0 * bytesPerPixel;

    CGFloat red   = (rawData[byteIndex]     * 1.0) / 255.0;
    CGFloat green = (rawData[byteIndex + 1] * 1.0) / 255.0;
    CGFloat blue  = (rawData[byteIndex + 2] * 1.0) / 255.0;
    CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;

    UIColor *acolor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];

    free(rawData);

    return acolor;
}

Now if I use this UIColor as the background instead of colorWithPatternImage, I can share to my heart's content without encountering this weird exception.

The above method was adapted from a solution that I found here: https://stackoverflow.com/a/1262893/1103584

Community
  • 1
  • 1
DiscDev
  • 38,652
  • 20
  • 117
  • 133
0

It's a bug of iOS 6 i report it and it was marked as dublicate. So, someone report that bug earlier.

Vlad Polyanskiy
  • 2,589
  • 2
  • 18
  • 21
0

For using pattern, you can use resizableImageWithCapInsets. In Monotouch it seems like this:

var sba = UISearchBar.Appearance;

var img = UIImage.FromBundle("myResource.png");

if (UIDevice.CurrentDevice.CheckSystemVersion(6, 0)) {
    img = img.CreateResizableImage(UIEdgeInsets.Zero, UIImageResizingMode.Tile);
    sba.BackgroundColor = UIColor.LightGray;
    sba.BackgroundImage = img;
} else {
    sba.BackgroundImage = new UIImage();
    sba.BackgroundColor = UIColor.FromPatternImage(img);
}
John
  • 1,447
  • 15
  • 16