Alex
Alex

Reputation: 1741

Complex preprocessor macro

I'm creating a category of UIColor where I have a set of colors that I want to access easily and then cache.

This is the basically how I create my colors:

#define RGB(r, g, b) [self colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]

// [..]

+ (instancetype)pigletColor
{
    static UIColor *pigletColor = nil;
    if (!pigletColor) {
        pigletColor = RGB(237.0, 0.0, 130.0);
    }
    return pigletColor;
}

However, repeating the above ten times is not really neat and dry so I'm trying to create a macro allowing me to do this easily.

Ideally, I'd like to replace the above with COLORGETTER(piglet, 234.0, 0.0, 130.0). I've had a go at it, but I can't get it to work. This is far as I got:

#define COLORGETTER(name, red, green, blue)\
+ (instancetype *)##name##Color\
{\
    static UIColor *##name##Color = nil;\
    if (!##name##Color) {\
        ##name##Color = RGB(red, green, blue);\
    }\
    return ##name##Color;\
}

However, the above doesn't work, as I can't figure out the #/## operators.

Any ideas?

Upvotes: 3

Views: 124

Answers (2)

Martin R
Martin R

Reputation: 540005

There are two errors:

  • (instancetype *) should be (instancetype). Similar to id, this is already a pointer.
  • ##name##Color should be name##Color. You want to concatenate the name and "Color" to a single token, but not the preceding token.

So this seems to work:

#define COLORGETTER(name, red, green, blue)\
    + (instancetype) name##Color\
    {\
        static UIColor * name##Color = nil;\
        if (!name##Color)\
        {\
            name##Color = RGB(red, green, blue);\
        }\
        return name##Color;\
    }

Upvotes: 3

Kevin
Kevin

Reputation: 56129

A few things

  1. instancetype is already a pointer, don't use instancetype *.
  2. You only need ## between identifieres - name ## Color, not ## name ## Color.
  3. You should really use a dispatch_once block instead of the if.
  4. Optional, but you don't really need the custom name for the locals. It's easier to just use one name.
#define COLORGETTER(name, red, green, blue)\
+ (UIColor *)name##Color\
{\
    static UIColor *color = nil;\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
        color = RGB(red, green, blue);\
    });\
    return color;\    
}

Upvotes: 3

Related Questions