iOS load和initialize的區別


可能有些還不清楚load和initialize的區別,下面簡單說一下:

首先說一下 + initialize 方法:蘋果官方對這個方法有這樣的一段描述:這個方法會在 第一次初始化這個類之前 被調用,我們用它來初始化靜態變量.

initialize方法的調用時機,當向該類發送第一個消息(一般是類消息首先調用,常見的是alloc)的時候,先調用類中的,再調用類別中的(類別中如果有重寫);如果該類只是引用,沒有調用,則不會執行initialize方法。
兩者方法的共同點:自動調用父類的,不需要super操作;自動調用僅僅會調用一次(不包括外部顯示調用).

load 方法會在加載類的時候就被調用,也就是 ios 應用啟動的時候,就會加載所有的類,就會調用每個類的 + load 方法.

load方法的調用時機,main函數之前,先調用類中的,再調用類別中的(類別中如果有重寫).

代碼演示:

#pragram ---main函數中的代碼---
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
  NSLog(@"%s",__func__);
  @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}


#pragram ---基於NSObject的Person類---
#import "Person.h"
@implementation Person
+ (void)load{
  NSLog(@"%s",__func__);
}
+ (void)initialize{
  [super initialize];
  NSLog(@"%s %@",__func__,[self class]);
}
- (instancetype)init{
  if (self = [super init]) {
      NSLog(@"%s",__func__);
  }
  return self;
}
@end



#pragram ---基於Person的Son類---
#import "Girl.h"
@implementation Girl
+ (void)load{
  NSLog(@"%s ",__func__);
}
+ (void)initialize{
  [super initialize];
  NSLog(@"%s ",__func__);
}
- (instancetype)init{
  if (self = [super init]) {
      NSLog(@"%s",__func__);
  }
  return self;
}
@end

輸出日志:

2017-07-07 09:28:36.535 initialize[1572:27457]] +[Person load]
2017-07-07 09:28:36.535 initialize[1572:27457]] +[Girl load] 
2017-07-07 09:28:36.535 initialize[1572:27457]] main

這說明在我並沒有對類做任何操作的情況下,+load 方法會被默認執行,並且是在 main 函數之前執行的。

 

#接下來我們來查看一下 + initialize 方法,先在 ViewController 中創建 Person 和 Girl 對象:

#import "ViewController.h"
#import "Person.h"
#import "Son.h"
#import "Girl.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  Person * p1 = [Person new];
  Person * p2 = [Person new];
  Girl *c1 = [Girl new];
  Girl *c2 = [Girl new];
}
@end

輸出日志:

2017-07-07 09:34:57.134 initialize[1840:100060] +[Person load]
2017-07-07 09:34:57.135 initialize[1840:100060] +[Girl load] 
2017-07-07 09:34:57.136 initialize[1840:100060] main
2017-07-07 09:34:57.198 initialize[1840:100060] +[Person initialize] Person
2017-07-07 09:34:57.198 initialize[1840:100060] -[Person init]
2017-07-07 09:34:57.198 initialize[1840:100060] -[Person init]
2017-07-07 09:34:57.198 initialize[1840:100060] +[Girl initialize] 
2017-07-07 09:34:57.199 initialize[1840:100060] -[Girl init]
2017-07-07 09:34:57.199 initialize[1840:100060] -[Girl init]

+ initialize 方法類似一個懶加載,如果沒有使用這個類,那么系統默認不會去調用這個方法,且默認只加載一次;

+ initialize 的調用發生在 +init 方法之前.

那么+ initialize 在父類與子類之間的關系是什么楊,我們創建一個繼承自 Person 類的 Son類:

#pragram ---ViewController 中的代碼---
#import "ViewController.h"
#import "Person.h"
#import "Son.h"
#import "Girl.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  Person * p1 = [Person new];
  Person * p2 = [Person new];
  Son*s = [Son new];
}
@end

輸出日志:

2017-07-07 09:50:14.140 initialize[1893:109979] +[Person load]
2017-07-07 09:50:14.142 initialize[1893:109979]  +[Son load]
2017-07-07 09:50:14.142 initialize[1893:109979]  +[Girl load] 
2017-07-07 09:50:14.142 initialize[1893:109979]  main
2017-07-07 09:50:14.203 initialize[1893:109979]  +[Person initialize] Person
2017-07-07 09:50:14.203 initialize[1893:109979] -[Person init]
2017-07-07 09:50:14.203 initialize[1893:109979]] -[Person init]
2017-07-07 09:50:14.204 initialize[1893:109979] +[Person initialize] Son
2017-07-07 09:50:14.204 initialize[1893:109979] -[Person init]

我們會發現 Person 類的 + initialize 方法又被調用了,但是查看一下是子類 Son 調用的,也就是創建子類的時候,子類會去調用父類的 + initialize 方法。

這是因為在創建子類對象時,首先要創建父類對象,所以會調用一次父類的initialize方法,然后創建子類時,盡管自己沒有實現initialize方法,但還是會調用到父類的方法。

雖然initialize方法對一個類而言只會調用一次,但這里由於出現了兩個類,所以調用兩次符合規則,但不符合我們的需求。正確使用initialize方法的姿勢如下

// In Person.m
+ (void)initialize {
    if (self == [Person class]) {
        NSLog(@"Initialize Person, caller Class %@", [self class]);
    }
}

加上判斷后,就不會因為子類而調用到自己的initialize方法了.

總結:

  1. loadinitialize方法都會在實例化對象之前調用,以main函數為分水嶺,前者在main函數之前調用,后者在之后調用。這兩個方法會被自動調用,不能手動調用它們。
  2. loadinitialize方法都不用顯示的調用父類的方法而是自動調用,即使子類沒有initialize方法也會調用父類的方法,而load方法則不會調用父類。
  3. load方法通常用來進行Method Swizzle,initialize方法一般用於初始化全局變量或靜態變量。
  4. loadinitialize方法內部使用了鎖,因此它們是線程安全的。實現時要盡可能保持簡單,避免阻塞線程,不要再使用鎖。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM