0

I have a .h file like this:

#import <UIKit/UIKit.h>
#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

long colorPresetHex = 0xdedede; // this is OK.
UIColor *colorPreset = UIColorFromRGB (colorPresetHex); // Error

This .h will be called from many places that requires this 'standard'. The problem is there's an error occurred on the line UIColor *colorPreset = UIColorFromRGB (colorPresetHex); said "initializer element is not a compile-time constant". Now I know why this is happened. What I want to do is how to work around this issue so that I can import this header file on any project and can immediately use the colorPreset variable. I've tried to put the initializer on .m, but it does not work either:

.h
#import <UIKit/UIKit.h>
#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

long colorPresetHex = 0xdedede; 
UIColor *colorPreset;

.m
#import ".h"
UIColor *colorPreset = UIColorFromRGB (colorPresetHex); // error: Redefinition of 'colorPreset'
colorPreset = UIColorFromRGB (colorPresetHex); // error: Redefinition of 'colorPreset' with different type: 'int' vs 'UIColor *__strong'

How can I work around this? I'd like to keep the initializer on this .h or .m, because I might copy these two files to another project, and if the initializer is in different class, that might make everything messy. Thanks.

Chen Li Yong
  • 5,459
  • 8
  • 58
  • 124
  • Please do not use macros and global variables. There are reasons why programmers stopped using them. – Sulthan Jan 22 '16 at 07:28
  • @Sulthan the only alternatives I know to avoid this global variable is just copy everything into every classes, initialise everything in every classes, even though I will never change it again throughout the app programmatically (sort of `const`). If I have to add, change, or remove a value, then I'll have to change it for every class I have, and double check to make sure that that one variable is changed in every class. That doesn't sound like something efficient for me. – Chen Li Yong Jan 22 '16 at 07:41
  • Nope. The trick is to use categories (e.g. `UIColor` category) and properties on singleton objects. The usage is the same but the code quality improves greately. – Sulthan Jan 22 '16 at 08:48

1 Answers1

1

You need the extern keyword. Here's an exhaustive explanation, but the short answer is to declare the variable in your header file like this:

extern UIColor *colorPreset;

Then define it in a .m file like this:

UIColor *colorPreset;

Then give set its value early in your program.

The extern means, "This variable is stored somewhere else." Without it, the compiler thinks that every .m file that imports your header is defining a new version of the variable with the same name, which is the "redefinition" in your error.

If you use extern, then you can define it in only one .m file and have no error.

Community
  • 1
  • 1
alltom
  • 3,162
  • 4
  • 31
  • 47
  • Can I have a way to set the value in the .m directly for the "non compile-time constant variables"? Or do I ultimately have to set the value in the first entry point of the program (that is within the class AppDelegate in my case)? – Chen Li Yong Jan 22 '16 at 07:43
  • 1
    You'll have to initialize it from the entry point. That's why it's conventional to expose computed constants like these as static methods instead of global variables. For example, [`[UIColor redColor]`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIColor_Class/#//apple_ref/occ/clm/UIColor/redColor) as opposed to `UIColorRed`. – alltom Jan 22 '16 at 07:47
  • I think you've just unexpectedly given me the answer I'm searching for. Thanks! – Chen Li Yong Jan 22 '16 at 07:54
  • 1
    Thanks to you, my code now much more cleaner using global class with static methods to return definitive values. I actually have just realised that I can just use global simple C functions to return those "non compile-time constant values", and use it to act like a variables, just like this methods. But this results in much simpler and more readable code. – Chen Li Yong Jan 22 '16 at 08:27