【问题标题】:In what order methods +initialize and +load called?以什么顺序调用方法 +initialize 和 +load?
【发布时间】:2019-05-27 05:06:43
【问题描述】:

假设我们有两个类:

@interface First : NSObject

@end

@interface Second : NSObject

@end

@implementation First
+(void)load
{
    NSLog(@"This must be called first");
}
@end

@implementation Second
+(void)load
{
    NSLog(@"And this must be called second");
}
@end

我们在每个类中都有+load 方法。如果我们运行这段代码,This must be called first 将是第一个,And this must be called second 将是第二个。

什么决定了这些类的+load 方法的调用顺序?在我的实验中,如果我在第一类的@implementation 之前移动第二类的@implementation - 首先打印And this must be called second,然后打印This must be called first。这是否意味着+load 订单仅取决于源代码中的订单?

在我的真实案例中,我使用自定义 +load 预编译了框架(在 main() 之前调用了一些代码,我看到了其中的日志),我需要在此代码之前执行我的代码(据我所知 - 我可以放到+load,但是不知道怎么改顺序)。或者我可以使用其他技术在框架代码之前调用我的代码吗?

【问题讨论】:

    标签: objective-c runtime objective-c-runtime


    【解决方案1】:

    +load 方法由 objc 运行时调用,作为图像加载过程的一部分(您可以通过中断 load 方法并打印堆栈跟踪来看到这一点。

    +load 方法的调用顺序似乎取决于 clang 生成的 objc 类列表的顺序。

    如果您查看 objc 运行时的源代码,您会看到 load_images(dyld 调用的函数)调用 prepare_load_methods 以获取图像中所有 objc 类的列表。 prepare_load_methods 调用 _getObjc2NonlazyClassList,它从图像中的 __objc_nlclslist 部分获取 objc 类列表。

    load_images 然后调用call_load_methods,它会遍历所有加载的类并调用它们的+load 方法。

    【讨论】:

    • 是的;订单是一个实施细节,可能会发生变化。即使您要恢复到当前顺序,也可能在发行版中不稳定。同样,任何起作用的动态加载都会有额外的加载阶段。
    【解决方案2】:

    你真的不能依赖秩序,你也不能有效地控制秩序。按设计。 +load 应该发生在之前该类的+initialize,但是它们两者的顺序在多个类中似乎是不确定的(我觉得有点令人惊讶,但在规则)。

    这是您不应该在+load+initialize 中做任何繁重工作的重要原因。它们真的应该只被谨慎使用,并且只用于初始化一小部分高度本地化的状态。接触其他重要子系统是危险的,因为您将以可能破坏系统的方式更改初始化顺序和行为。不应该,但它可能,它可以,而且过去是这样。

    相反,您确实应该尝试在您的框架代码中设置一个客户端显式调用的“从这里开始”点。

    【讨论】:

    • 可能值得指出的是,基类的 +load 和 +initialize 在其子类之前调用​​也是有保证的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 2015-12-01
    • 2012-05-14
    • 2012-04-04
    • 2012-01-20
    • 1970-01-01
    相关资源
    最近更新 更多