Chazbot
Chazbot

Reputation: 1890

Can't subclass UIColor?

I'm trying to subclass UIColor, and I can't seem to figure out what's wrong.

In my PColor.h

#import <Foundation/Foundation.h>
@interface PColor : UIColor {
    BOOL isAvailable;
    int colorId;
}
@property (nonatomic, assign) BOOL isAvailable;
@property (nonatomic, assign) int colorId;
@end

...and in my PColor.m

#import "PColor.h"

@implementation PColor
@synthesize isAvailable;
@synthesize colorId;
@end

Upon instantiating a PColor object, I get:

//warning: incompatible Objective-C types initializing 'struct UIColor *', expected 'struct PColor *'
PColor *pcolor = [[PColor alloc] initWithHue:1 saturation:0 brightness:0 alpha:1];

Am I missing something? Thanks in advance.

Upvotes: 3

Views: 2374

Answers (4)

Joe
Joe

Reputation: 57169

UIColor is a class cluster use associative references in a category to add properties! All of the custom init methods on UIColor return a UIColor* not an id so you can not easily subclass UIColor nor should you try.

UIColor+PCOLOR.h

#import <UIKit/UIKit.h>
#import <objc/runtime.h>

@interface UIColor(PCOLOR)
//Properties prefixed to try and avoid future conflicts
@property (nonatomic, assign) BOOL pIsAvailable;
@property (nonatomic, assign) int pColorId;
@end

UIColor+PCOLOR.h

#import "UIColor+PCOLOR.h"

@implementation UIColor(PCOLOR)

static char PCOLOR_ISAVAILABLE_KEY;
static char PCOLOR_COLORID_KEY;

@dynamic pIsAvailable, pColorId;

-(void)setPIsAvailable:(BOOL)pIsAvailable
{
    objc_setAssociatedObject(self, &PCOLOR_ISAVAILABLE_KEY, [NSNumber numberWithBool:pIsAvailable], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(BOOL)pIsAvailable
{
    return [(NSNumber*)objc_getAssociatedObject(self, &PCOLOR_ISAVAILABLE_KEY) boolValue];
}

-(void)setPColorId:(int)pColorId
{
    objc_setAssociatedObject(self, &PCOLOR_COLORID_KEY, [NSNumber numberWithInt:pColorId], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(int)pColorId
{
    return  [(NSNumber*)objc_getAssociatedObject(self, &PCOLOR_COLORID_KEY) intValue];
}

@end

USAGE

UIColor *pcolor = [[UIColor alloc] initWithHue:1 saturation:0 brightness:0 alpha:1];
pcolor.pColorId = 2352;
pcolor.pIsAvailable = YES;
NSLog(@"\nClass: %@\nColor ID: %d\nIs Availabled: %@", 
      NSStringFromClass([pcolor class]), 
      pcolor.pColorId, 
      pcolor.pIsAvailable ? @"YES" : @"NO");
[pcolor release];

Upvotes: 6

Michael Behan
Michael Behan

Reputation: 3443

The init methods of UIColor return a UIColor* rather than id as with most classes, so you would have to assign it to a UIColor rather than your subclass to avoid the warning.

Upvotes: 0

Black Frog
Black Frog

Reputation: 11703

From UIColor Class Reference:

Most developers should have no need to subclass UIColor. The only time doing so might be necessary is if you require support for additional colorspaces or color models.

You should use Category. For example:

@interface UIColor (PColor)
    - (BOOL) isAvailable;
    - (int) colorId;
@end

In the implementation file:

@implementation UIColor (PColor)

    - (BOOL)isAvailable {
        // do what you want to do
        // return your BOOL
    }

    - (int)colorId  {
        // do what you want to do
        // return id of color
    }

@end

Upvotes: 5

Tomasz Stanczak
Tomasz Stanczak

Reputation: 13164

Because UIColor alloc might not do what you expect it to do: allocating an instance of UIColor. It may be kind of a factory method, which looks first what colors have already been used or belong to a standard set of colors and give it back instead of creating a new instance. In which case you will be getting UIColor instead of PColors and what means that inheriting UIColor was not a good idea.

Prefer composition over inheritance - embed UIColor within a PColor. Or use a category on UIColor (you can't have new instance variables in this case).

Upvotes: 1

Related Questions