Objective C类方法load和initialize问题集合

一.  版本1   

  在Objective-C中,NSObject是根类,而NSObject.h的头文件中前两个方法就是load和initialize两个类方法,本篇文章就对这两个方法做下说明和整理。Objective-C作为一门面向对象语言,有类和对象的概念。编译后,类相关的数据结构会保留在目标文件中,在运行时得到解析和使用。在应用程序运行起来的时候,类的信息会有加载和初始化过程。

就像Application有生命周期回调方法一样,在Objective-C的类被加载和初始化的时候,也可以收到方法回调,可以在适当的情况下做一些定制处理。而这正是load和initialize方法可以帮我们做到的。

1
2
+ (void)load;
+ (void)initialize;

1. load和initialize的共同特点

  • 在不考虑开发者主动使用的情况下,系统最多会调用一次

  • 如果父类和子类都被调用,父类的调用一定在子类之前

  • 都是为了应用运行提前创建合适的运行环境

  • 在使用时都不要过重地依赖于这两个方法,除非真正必要

2. load方法相关要点

       调用时机比较早,运行环境有不确定因素。具体说来,在iOS上通常就是App启动时进行加载,但当load调用的时候,并不能保证所有类都加载完成且可用,必要时还要自己负责做auto release处理。

       对于有依赖关系的两个库中,被依赖的类的load会优先调用。但在一个库之内,调用顺序是不确定的。

  • 对于一个类而言,没有load方法实现就不会调用,不会考虑对NSObject的继承。

  • 一个类的load方法不用写明[super load],父类就会收到调用,并且在子类之前。

  • Category的load也会收到调用,但顺序上在主类的load调用之后。

  • 不会直接触发initialize的调用。

3. initialize方法相关要点

  • initialize的自然调用是在第一次主动使用当前类的时候(lazy,这一点和Java类的“clinit”的很像)。

  • 在initialize方法收到调用时,运行环境基本健全。

  • initialize的运行过程中是能保证线程安全的。

  • 和load不同,即使子类不实现initialize方法,会把父类的实现继承过来调用一遍。注意的是在此之前,父类的方法已经被执行过一次了,同样不需要super调用。

4.[  A  alloc];

alloc将为A类实例在堆上分配变量。这时调用一次initialize方法,而且调用一次,也就是说再次alloc操作的时候,不会再调用initialize方法了。

initialize 会在运行时仅被触发一次,如果没有向类发送消息的话,这个方法将不会被调用。这个方法的调用是线程安全的。父类会比子类先收到此消息

 

如果希望在类及其Categorgy中执行不同的初始化的话可以使用

+(void)load; Objective-C运行时载入类或者Category时被调用

这个方法对动态库和静态库中的类或(Category)都有效.

 

Mac OS X 10.5及之后的版本,初始化的顺序如下:

1. 调用所有的Framework中的初始化方法

2. 调用所有的+load方法

3. 调用C++的静态初始化方及C/C++中的__attribute__(constructor)函数

4. 调用所有链接到目标文件的framework中的初始化方法

另外

一个类的+load方法在其父类的+load方法后调用

一个Category+load方法在被其扩展的类的自有+load方法后调用

+load方法中,可以安全地向同一二进制包中的其它无关的类发送消息,但接收消息的类中的+load方法可能尚未被调用。


5.为什么没有执行类中的initialize而是执行Category中的initialize方法??(Category覆盖方法时优先级更高)


二.版本2

initialize和load的区别在于:load是只要类所在文件被引用就会被调用,而initialize是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用;但即使类文件被引用进来,但是没有使用,那么initialize也不会被调用。


7.总结:            调用级别先后,父类>子类>分类
              
  1. + (void)initialize 消息是在该类接收到其第一个消息之前调用。关于这里的第一个消息需要特别说明一下,对于 NSObject 的 runtime 机制而言,其在调用 NSObject 的 + (void)load 消息不被视为第一个消息,但是,如果像普通函数调用一样直接调用 NSObject 的 + (void)load 消息,则会引起 + (void)initialize 的调用。反之,如果没有向 NSObject 发送第一个消息,+ (void)initialize 则不会被自动调用。
  2. 在应用程序的生命周期中,runtime 只会向每个类发送一次 + (void)initialize 消息,如果该类是子类,且该子类中没有实现 + (void)initialize 消息,或者子类显示调用父类实现 [super initialize], 那么则会调用其父类的实现。也就是说,父类的 + (void)initialize 可能会被调用多次。
  3. 如果类包含分类,且分类重写了initialize方法,那么则会调用分类的 initialize 实现,而原类的该方法实现不会被调用,这个机制同 NSObject 的其他方法(除 + (void)load 方法) 一样,即如果原类同该类的分类包含有相同的方法实现,那么原类的该方法被隐藏而无法被调用。
  4. 父类的 initialize 方法先于子类的 initialize 方法调用。
  5. 如果你没有用到你重写的这个控制器.那你重写的load类方法也会调用.换句话说,这个load方法是在didFinishLaunchingWithOptions方法之前就被调用了.

    用法:load类方法,歌没有用过.只是用过initialize类方法.所以....

      initialize类方法的一个金典应用:

        往往在一个应用APP中,导航条控制器的导航条几乎是统一的.再加上,一般情况一个应用APP会重写一个导航控制器类.那么initialize类方法就能出场了.比如:

    + (void)initialize {

        NSLog(@"%s:%s",__FILE__,__func__);

        //设置导航栏主题

        UINavigationBar *navBar = [UINavigationBar appearance];

        //接下来就可以对navBar坐各种统一的设置处理了.比如字体,背景....

    }


    三.版本3

    load--当类被引用进程序的时候会执行这个函数。

    当父类和子类都实现load函数时,父类的load函数会被先执行。load函数是系统自动加载的,因此不需要调用父类的load函数,否则父类的load函数会多次执行

    在Category中写load函数是不会替换原始类中的load函数的,原始类和Category中的load函数都会被执行,原始类的load会先被执行,再执行Category中的load函数。当有多个Category都实现了load函数,这几个load函数执行顺序不确定。

    initialize--当类第一次被执行到的时候这个函数会被执行。

    如果类包含继承关系,父类的initialize函数会比子类先执行。由于是系统自动调用,也不需要显式的调用父类的initialize,否则父类的initialize会被多次执行

    假如这个类放到代码中,而这段代码并没有被执行,这个函数是不会被执行的。

    Load or Initialize

    这两个函数没有交集,也没有执行的先后顺序,他们各自遵循着各自的调用原则。因此在写逻辑的时候,不能有逻辑依赖load函数比initialize函数先行调用

    使用场景:

    将针对于类修改放在intialize中,将针对Category的修改放在load中。

    但是假如我们是修改系统的类,一般会通过添加Category来添加功能,但是如果修改initialize会导致原生的intialize不会执行,所以放在load中会比较妥当。



    四.版本4

    load

    load方法在这个文件被程序装载时调用。只要是在Compile Sources中出现的文件总是会被装载,这与这个类是否被用到无关,因此load方法总是在main函数之前调用。

    调用规则

    如果一个类实现了load方法,在调用这个方法前会首先调用父类的load方法。而且这个过程是自动完成的,并不需要我们手动实现:

     
         

    如果一个类没有实现load方法,那么就不会调用它父类的load方法,这一点与正常的类继承和方法调用不一样,需要额外注意一下。

    执行顺序

    load方法调用时,系统处于脆弱状态,如果调用别的类的方法,且该方法依赖于那个类的load方法进行初始化设置,那么必须确保那个类的load方法已经调用了


  6. loadinitialize方法都会在实例化对象之前调用,以main函数为分水岭,前者在main函数之前调用,后者在之后调用。这两个方法会被自动调用,不能手动调用它们。
  7. loadinitialize方法都不用显示的调用父类的方法而是自动调用,即使子类没有initialize方法也会调用父类的方法,而load方法则不会调用父类。
  8. load方法通常用来进行Method Swizzle,initialize方法一般用于初始化全局变量或静态变量。
  9. loadinitialize方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。


你可能感兴趣的:(Objective C类方法load和initialize问题集合)