Objective-C Is it safe to overwrite [NSObject initialize]?

爷,独闯天下 提交于 2019-12-18 04:23:12

问题


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?


回答1:


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.




回答2:


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.




回答3:


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.



来源:https://stackoverflow.com/questions/4668887/objective-c-is-it-safe-to-overwrite-nsobject-initialize

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!