Objective-C 覆盖[NSObject初始化]是否安全?

发布于 2024-10-11 18:42:03 字数 738 浏览 5 评论 0原文

基本上,我有以下代码(此处解释:协议中的 Objective-C 常量

// 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

我想知道:拥有一个覆盖 NSObject 的 +initialize 方法的类别对我来说安全吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

栖迟 2024-10-18 18:42:03

简而言之,不,您无法在类的类别中安全地实现 +initialize 方法。您最终将替换现有的实现(如果有),并且如果一个类的两个类别都实现了 +initialize,则无法保证哪一个会被执行。

+load 具有更可预测和定义明确的行为,但发生得太早而无法做任何有用的事情,因为很多事情都处于未初始化状态。

就我个人而言,我完全跳过 +load+initialize 并使用编译器注释来导致在加载底层二进制文件/dylib 时执行函数。不过,此时您能安全地做的事情仍然很少。

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

您最好根据启动的应用程序进行初始化。 NSApplicationUIApplication 都提供委托/通知挂钩,用于在应用程序启动时向应用程序注入一些代码。

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.

拔了角的鹿 2024-10-18 18:42:03

为什么不在 MyClass 类中设置这两个变量呢?另外,为什么不使用访问器?最好在实际使用它的类上定义一个访问器,而不是使用一个不知从何而来的假常量。一个简单的 +(NSString *)myProtocolSize;即使在协议中也会做得很好。

此外,重写类别中类的方法“有效”,但不可靠,应不惜一切代价避免:如果您要重写的方法是在类别中实现的,则运行时不保证加载顺序和您的实现可能永远不会被添加到其中。

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.

梦途 2024-10-18 18:42:03

假设我们暂时忽略 C++ 的异常情况,NSString *const 类型的变量将始终在代码运行之前进行初始化:

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

const NSString * 类型的变量(const NSString * >const 关键字应用于 NSString 的内部,而不是其地址)可以由任何代码修改,但不能向其发送消息。它违背了使其成为 const 的目的。考虑使用全局函数:

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

或者使用类方法:

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

您之前问过一个关于为什么您的 const 字符串不接受动态值的问题 - 这是因为您似乎不了解 const 对符号起作用。您应该阅读 C 语言中 const 关键字的含义,并且如果 const 不正确,则应该考虑另一种获取字符串的方法。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文