类的加载

在java语言里,可以通过如下代码来实现加载类的时候执行对类的操作,一般叫:类初始块,或者,类加载块。比如:

 

代码 

1 public class MyClass{    
2     static{    
3         ……    
4     }    
5 }

 

在objc语言里,对应的机制是,2个类初始化方法,+(void)load和+(void)initialize。

比如:

 

代码 

1 #import "Constants.h"    
 2 @implementation Constants    
 3   
 4 + (void)initialize{    
 5     NSLog(@"init constants >>>>>>>>>>");    
 6 }    
 7   
 8 + (void)load{    
 9     NSLog(@"load constants >>>>>>>>>>");    
10 }    
11   
12 @end

 

 两个方法有一些不同。

load,是加载类的时候,这里是Constants类,就会调用。也就是说,ios应用启动的时候,就会加载所有的类,就会调用这个方法。

 

这样有个缺点,当加载类需要很昂贵的资源,或者比较耗时的时候,可能造成不良的用户体验,或者系统的抖动。这时候,就要考虑initialize方法了。这个方法可看作类加载的延时加载方法。类加载后并不执行该方法。只有当实例化该类的实例的时候,才会在第一个实例加载前执行该方法。比如:

 

 

[Constants alloc];

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

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

 

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

+(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方法可能尚未被调用。

 

下面是一个load的顺序

代码 

1 #import <Foundation/Foundation.h>    
 2   
 3 #define LOAD +(void)load{NSLog(@"%s", __PRETTY_FUNCTION__);}    
 4 #define INITIALIZE +(void)initialize{NSLog(@"%s", __PRETTY_FUNCTION__);}    
 5 #define DEF_CLASS(clsName) @interface clsName : NSObject \    
 6 @end \    
 7 @implementation clsName \    
 8 INITIALIZE \    
 9 LOAD \    
10 @end    
11   
12 DEF_CLASS(C1)   //1    
13 DEF_CLASS(C2)   //2    
14   
15 @interface C1 (Hello)    
16 + (void)hello;    
17 @end    
18 @implementation C1 (Hello)    
19 INITIALIZE       //   
20 LOAD            //3    
21 + (void)hello    
22 {    
23     NSLog(@"Hello");    
24 }    
25 + (void)hi    
26 {    
27     NSLog(@"hi");    
28 }    
29 @end    
30   
31 @interface C2 (Hello)    
32 @end    
33 @implementation C2 (Hello)    
34 + (void)load    //4   
35 {    
36     NSLog(@"%s", __PRETTY_FUNCTION__);    
37 }    
38   
39 + (void)initialize    //   
40 {    
41     NSLog(@"%s", __PRETTY_FUNCTION__);    
42 }    
43 @end    
44 int main (int argc, const char * argv[])    
45 {    
46       
47     @autoreleasepool {    
48         // insert code here...    
49         //        [[C1 alloc]init]; // 向C1发送消息    
50         //       [[C2 alloc]init]; // 向C2发送消息    
51     }    
52     return 0;    
53 }

 

 输出:

2012-08-14 00:47:07.859 www[654:903] +[C1 load]

2012-08-14 00:47:07.862 www[654:903] +[C2 load]

2012-08-14 00:47:07.863 www[654:903] +[C1(Hello) load]

2012-08-14 00:47:07.863 www[654:903] +[C2(Hello) load]

以上只执行了load方法。

 

 

load和initialize的顺序:

代码 

1  
 2 #import <Foundation/Foundation.h>    
 3   
 4 #define LOAD +(void)load{NSLog(@"%s", __PRETTY_FUNCTION__);}    
 5 #define INITIALIZE +(void)initialize{NSLog(@"%s", __PRETTY_FUNCTION__);}    
 6 #define DEF_CLASS(clsName) @interface clsName : NSObject \    
 7 @end \    
 8 @implementation clsName \    
 9 INITIALIZE \    
10 LOAD \    
11 @end    
12   
13 DEF_CLASS(C1)   //1    
14 DEF_CLASS(C2)   //2    
15   
16 @interface C1 (Hello)    
17 + (void)hello;    
18 @end    
19 @implementation C1 (Hello)    
20 INITIALIZE       //4    
21 LOAD            //3    
22 + (void)hello    
23 {    
24     NSLog(@"Hello");    
25 }    
26 + (void)hi    
27 {    
28     NSLog(@"hi");    
29 }    
30 @end    
31   
32 @interface C2 (Hello)    
33 @end    
34 @implementation C2 (Hello)    
35 + (void)load    //5    
36 {    
37     NSLog(@"%s", __PRETTY_FUNCTION__);//[C1 hello];//NSLog(@"%s", __PRETTY_FUNCTION__);    
38 }    
39   
40 + (void)initialize    //6    
41 {    
42     NSLog(@"%s", __PRETTY_FUNCTION__);    
43 }    
44 @end    
45 int main (int argc, const char * argv[])    
46 {    
47       
48     @autoreleasepool {    
49         // insert code here...    
50         [[C1 alloc]init]; // 向C1发送消息    
51         [[C2 alloc]init]; // 向C2发送消息    
52     }    
53     return 0;    
54 }

 

 输出:

2012-08-14 00:55:26.769 www[741:903] +[C1 load]

2012-08-14 00:55:26.772 www[741:903] +[C2 load]

2012-08-14 00:55:26.772 www[741:903] +[C1(Hello) load]

2012-08-14 00:55:26.773 www[741:903] +[C2(Hello) load]

2012-08-14 00:55:26.773 www[741:903] +[C1(Hello) initialize]

2012-08-14 00:55:26.774 www[741:903] +[C2(Hello) initialize]

 

貌似类中的initialize没有执行。alloc]init某个类就调用每个类的initialize方法。

假如只[[C2 alloc]init];就只执行C2类中的initialize方法

 

2012-08-14 00:55:26.769 www[741:903] +[C1 load]

2012-08-14 00:55:26.772 www[741:903] +[C2 load]

2012-08-14 00:55:26.772 www[741:903] +[C1(Hello) load]

2012-08-14 00:55:26.773 www[741:903] +[C2(Hello) load]

2012-08-14 00:55:26.774 www[741:903] +[C2(Hello) initialize]

  

再看下面代码:

 

代码 

1 #import <Foundation/Foundation.h>    
 2   
 3 #define LOAD +(void)load{NSLog(@"%s", __PRETTY_FUNCTION__);}    
 4 #define INITIALIZE +(void)initialize{NSLog(@"%s", __PRETTY_FUNCTION__);}    
 5 #define DEF_CLASS(clsName) @interface clsName : NSObject \    
 6 @end \    
 7 @implementation clsName \    
 8 INITIALIZE \    
 9 LOAD \    
10 @end    
11   
12 DEF_CLASS(C1)   //1    
13 DEF_CLASS(C2)   //2    
14   
15 @interface C1 (Hello)    
16 + (void)hello;    
17 @end    
18 @implementation C1 (Hello)    
19 INITIALIZE       //4    
20 LOAD            //3    
21 + (void)hello    
22 {    
23     NSLog(@"Hello");    
24 }    
25 + (void)hi    
26 {    
27     NSLog(@"hi");    
28 }    
29 @end    
30   
31 @interface C2 (Hello)    
32 @end    
33 @implementation C2 (Hello)    
34 + (void)load    //5    
35 {    
36     [C1 hello];//NSLog(@"%s", __PRETTY_FUNCTION__); //这里做了修改,调用了C1的静态方法,导致执行了C1的+initialize   
37 }    
38   
39 + (void)initialize    //6    
40 {    
41     NSLog(@"%s", __PRETTY_FUNCTION__);    
42 }    
43 @end    
44 int main (int argc, const char * argv[])    
45 {    
46       
47     @autoreleasepool {    
48         // insert code here...    
49         //                [[C1 alloc]init]; // 向C1发送消息    
50         [[C2 alloc]init]; // 向C2发送消息    
51     }    
52     return 0;    
53 }

 

 输出:

2012-08-14 23:31:28.834 www[14975:903] +[C1 load]

2012-08-14 23:31:28.837 www[14975:903] +[C2 load]

2012-08-14 23:31:28.837 www[14975:903] +[C1(Hello) load]

2012-08-14 23:31:28.838 www[14975:903] +[C1(Hello) initialize]

2012-08-14 23:31:28.838 www[14975:903] Hello

2012-08-14 23:31:28.839 www[14975:903] +[C2(Hello) initialize]

 

问题:

1,在倒数第二个代码中,为什么没有执行类中的initialize而是执行Category中的initialize方法??(Category覆盖方法时优先级更高)