Question

Basically, I have the following code (explained here: Objective-C Constants in Protocol)

// MyProtocol.m
const NSString *MYPROTOCOL_SIZE;
const NSString *MYPROTOCOL_BOUNDS;

@implementation NSObject(initializeConstantVariables)

+(void) initialize {
     if (self == [NSObject class])
     {
         NSString **str = (NSString **)&MYPROTOCOL_SIZE;
         *str = [[MyClass someStringLoadedFromAFile] stringByAppendingString:@"size"];
         str = (NSString **)&MYPROTOCOL_BOUNDS;
         *str = [[MyClass someStringLoadedFromAFile] stringByAppendingString:@"bounds"];
     }
}

@end

I was wondering: Is it safe for me to have a category that overrides the NSObject's +initialize method?

Was it helpful?

Solution

In short, no, you cannot safely implement +initialize methods in categories on classes. You'll end up replacing an existing implementation, if there is one, and if two categories of one class both implement +initialize, there is no guarantee which will be executed.

+load has more predictable and well-defined behavior, but happens too early to do anything useful because so many things are in an uninitialized state.

Personally, I skip +load or +initialize altogether and use a compiler annotation to cause a function to be executed on load of the underlying binary/dylib. Still, there is very little you can do safely at that time.

__attribute__((constructor))
static void MySuperEarlyInitialization() {...}

You are far better off doing your initialization in response to the application being brought up. NSApplication and UIApplication both offer delegate/notification hooks for injecting a bit of code into the app as it launches.

OTHER TIPS

Why don't you setup those two variables inside the class MyClass instead ? And also, why don't you use accessors ? Instead of having a fake constant variable that comes from nowhere, it's preferable to define an accessor on a class that should actually use it. A simple +(NSString *)myProtocolSize; would do great, even in the protocol.

Also, overriding methods of a class in a category "works" but isn't reliable and should be avoided at all cost: if the method you're overriding is implemented in a category, the runtime does NOT guarantee the loading order and your implementation might never be added to it.

A variable of type NSString *const will always be initialized before your code runs, assuming we ignore C++ vagaries for the moment:

NSString *const MY_PROTOCOL_SIZE = @"...";

A variable of type const NSString * (the const keyword applying to the guts of the NSString, not its address) can be modified by any code, but cannot have messages sent to it. It defeats the purpose of making it const. Consider instead a global function:

static NSString *GetMyProtocolSize(void) {
    return [[MyClass someStringLoadedFromAFile] ...];
}

Or use a class method:

@implementation MyClass
+ (NSString *)myProtocolSize {
    return [[MyClass someStringLoadedFromAFile] ...];
}
@end

You asked a question earlier about why your const strings wouldn't accept dynamic values--this is because you do not seem to understand what const does to a symbol. You should read up on the meaning of the const keyword in C and should look at another approach to getting your strings if const is not the right one.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top