views:

291

answers:

3

I have the following code in the view controller:

- (void)viewDidLoad {
    [super viewDidLoad];
 ThemeManager *themer = [ThemeManager sharedInstance];
 UIView *theView = self.view;
 UIColor *forBackground = [themer backgroundColour];
 [theView setBackgroundColor:forBackground];
}

but when execution gets to the setBackgroundColor line, I get the following error:

*** -[NSCFNumber CGColor]: unrecognized selector sent to instance 0x1237c40
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFNumber CGColor]: unrecognized selector sent to instance 0x1237c40'

There's got to be something simple that I'm doing wrong, how do I set the background colour?

Do I have to subclass the view and do it in there? I'd prefer not to have the extra class, even though that is better separation of the whole model/view/controller thing.

Update: value returned by [themer backgroundColour] is constructed using colorWithPatternImage:, could this make a difference?

Update: if I use a value in my ThemeManager that was constructed using colorWithRed:green:blue:alpha:, that it works OK. Is there any way to do this using a color with a background image? The following works OK:

[theView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"myimage.png"]]];

Update: this works OK too:

UIColor *forBackground = [UIColor colorWithPatternImage:[UIImage imageNamed:@"myimage.png"]];
[theView setBackgroundColor:forBackground];

In my original example, the object returned from [themer backgroundColor] was a UIColor, so what's the problem?

When I step through with the debugger:

UIColor *forBackground = [themer backgroundColour];

results in forBackground being of type NSConstantValueExpression *

and

UIColor *forBackground = [UIColor colorWithPatternImage:[UIImage imageNamed:@"myimage.png"]];

results in forBackground being of type UIDeviceRGBColor *

Here is the code for the ThemeManager's backgroundColour method:

- (UIColor *)backgroundColour {
 if (backgroundColour == nil) {
  backgroundColour = [UIColor colorWithPatternImage:[UIImage imageNamed:@"myimage.png"]];
 }

 return backgroundColour;
}

backgroundColour is also the name of an instance variable.

A: 

It seems that this line returns an invalid instance:

UIColor *forBackground = [themer backgroundColour];

The error says that forBackground is of class NSCFNumber and not of class UIColor class as expected. Please check that the backgroundColour method returns the correct type.

Update:

Have you checked the value of backgroundColour in the debugger for this method ?

- (UIColor *)backgroundColour {
    if (backgroundColour == nil) {
        backgroundColour = [UIColor colorWithPatternImage:[UIImage imageNamed:@"myimage.png"]];
    }
    return backgroundColour;
}

I suspect that backgroundColour is not set to null when the instance is created. So the test fails and the method returns a random reference.

Laurent Etiemble
The debugger stops with the red arrow on the line containing setBackgroundColor
Curyous
You build the pattern color only if backgroundColour is nil. Are you sure that backgroundColour is nil ? If you put a breakpoint on the line that create the color, does the debugger stop ?
Laurent Etiemble
Good point, I've moved the colour generating code to the init method, a better solution anyway, even though it wasn't the root cause of this problem.
Curyous
A: 

Hi I might seems as if the themer returns a Number instead of a color, maybe the themer deals in RGB hex values?

I sometimes build a customColor class with a Class Method + (UIColor*)getCustomColor:(CustomColorType) color; that I use once the color theme of the app is determined, it also gives you the benefit of being able to change colors one place and have the change be instant everywhere. I usually do this in 0xFFFFFFFF values as that is how most designers deal with the color.

This is "Copy-wasted" from my last project:

//
//  CustomColor.h
//  FC
//
//  Created by RickiG on 12/19/09.
//  Copyright 2009 www.rickigregersen.com.. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef enum {

    CustomColorWhiteText, 
    CustomColorDarkGreyText, 
    CustomColorLightGreyText,
    CustomColorGreyText,
    CustomColorLightBlueText,
    CustomColorDarkWhiteText,
    CustomColorLightWhiteText,
    CustomColorLightPurpleText, 
    CustomColorOrange,
    CustomColorRed,
    CustomColorSilver,

} CustomColorType;

@interface CustomColor : NSObject {

}

+ (UIColor*) getCustomColor:(CustomColorType) color;

@end

And the implementation:

//
//  CustomColor.m
//  FC
//
//  Created by RickiG on 12/19/09.
//  Copyright 2009 www.rickigregersen.com.. All rights reserved.
//

#import "CustomColor.h"


@implementation CustomColor

+ (UIColor*) getCustomColor:(CustomColorType) color {

    int value;

    switch (color) {

        case CustomColorWhiteText:
            value = 0xffffff;
            break;          
        case CustomColorDarkGreyText:
            value = 0x373737;
            break;
        case CustomColorGreyText:
            value = 0x7a7a7a;
            break;
        case CustomColorLightGreyText:
            value = 0xd3d3d3;
            break;          
        case CustomColorLightBlueText:
            value = 0x8ed6ff;
            break;  
        case CustomColorDarkWhiteText:
            value = 0x979797;
            break;  
        case CustomColorLightWhiteText:
            value = 0xe8e8e8;
            break;
        case CustomColorLightPurpleText:
            value = 0xd17efc;
            break;
        case CustomColorOrange:
            value = 0xfb8720;
            break;
        case CustomColorRed:
            value = 0xeb0008;
            break;
        case CustomColorSilver:
            value = 0xe3e3e3;
            break;

        default:
            value = 0x000000;
            break;
    }

    int r, g, b;
    b = value & 0x0000FF;
    g = ((value & 0x00FF00) >> 8);
    r = ((value & 0xFF0000) >> 16);

    return [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f];
}

@end

This way I can always go:

[UIView setBackgroundColor:[CustomColor getCustomColor:CustomColorWhiteText];

From anywhere in my project. I have the same type of file to deal with textlabels, buttons and other interface elements that are reused through an app.

Hope it helps if you are building a UI that should be able to change it's appearance on the fly, even though it was not exactly what you asked:)

RickiG
A: 

The problem was that I did not retain the UIColor in the ThemeManager, so it worked on the first view, but not subsequent ones.

New code in ThemeManager:

backgroundColour = [[UIColor colorWithPatternImage:[UIImage imageNamed:@"myimage.png"]] retain];
Curyous