1. 程式人生 > >iOS - +load與+ initialize -init

iOS - +load與+ initialize -init

一、+ initialize 方法和+load 呼叫時機

  • 首先說一下 + initialize 方法:蘋果官方對這個方法有這樣的一段描述:這個方法會在 第一次初始化這個類之前 被呼叫,我們用它來初始化靜態變數。
    • load 方法會在載入類的時候就被呼叫,也就是 ios 應用啟動的時候,就會載入所有的類,就會呼叫每個類的 + load 方法。
  • 之後我們結合程式碼來探究一下 + initialize 與 + load 兩個方法的呼叫時機,首先是 + load
    #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
    執行程式,我們看一下輸出日誌:
    
    2015-10-27 15:21:07.545 initialize[11637:334237] +[Person load]
    2015-10-27 15:21:07.546 initialize[11637:334237] +[Girl load] 
    2015-10-27 15:21:07.546 initialize[11637:334237] 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 * a = [Person new];
      Person * b = [Person new];
      Girl *c = [Girl new];
      Girl *d = [Girl new];
    }
    @end
    下面我們來看一下輸出日誌:
    
    2015-10-27 15:33:56.195 initialize[11711:342410] +[Person load]
    2015-10-27 15:33:56.196 initialize[11711:342410] +[Girl load] 
    2015-10-27 15:33:56.197 initialize[11711:342410] main
    2015-10-27 15:33:56.259 initialize[11711:342410] +[Person initialize] Person
    2015-10-27 15:33:56.259 initialize[11711:342410] -[Person init]
    2015-10-27 15:33:56.259 initialize[11711:342410] -[Person init]
    2015-10-27 15:33:56.259 initialize[11711:342410] +[Girl initialize] 
    2015-10-27 15:33:56.260 initialize[11711:342410] -[Girl init]
    2015-10-27 15:33:56.260 initialize[11711:342410] -[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 * a = [Person new];
      Person * b = [Person new];
      Son*z = [Son new];
    }
    @end
    看一下輸出日誌:
    
    2015-10-27 15:44:55.762 initialize[12024:351576] +[Person load]
    2015-10-27 15:44:55.764 initialize[12024:351576] +[Son load]
    2015-10-27 15:44:55.764 initialize[12024:351576] +[Girl load] 
    2015-10-27 15:44:55.764 initialize[12024:351576] main
    2015-10-27 15:44:55.825 initialize[12024:351576] +[Person initialize] Person
    2015-10-27 15:44:55.825 initialize[12024:351576] -[Person init]
    2015-10-27 15:44:55.825 initialize[12024:351576] -[Person init]
    2015-10-27 15:44:55.826 initialize[12024:351576] +[Person initialize] Son
    2015-10-27 15:44:55.826 initialize[12024:351576] -[Person init]
    我們會發現 Person 類的 + initialize 方法又被呼叫了,但是檢視一下是子類 Son 呼叫的,也就是建立子類的時候,子類會去呼叫父類的 + initialize 方法。

二、總結

  • 如果你實現了 + load 方法,那麼當類被載入時它會自動被呼叫。這個呼叫非常早。如果你實現了一個應用或框架的 + load,並且你的應用連結到這個框架上了,那麼 + load 會在 main() 函式之前被呼叫。如果你在一個可載入的 bundle 中實現了 + load,那麼它會在 bundle 載入的過程中被呼叫。
  • + initialize 方法的呼叫看起來會更合理,通常在它裡面寫程式碼比在 + load 裡寫更好。+ initialize 很有趣,因為它是懶呼叫的,也有可能完全不被呼叫。類第一次被載入時,
  • + initialize 不會被呼叫。類接收訊息時,執行時會先檢查 + initialize 有沒有被呼叫過。如果沒有,會在訊息被處理前呼叫。

 

文/Mitchell(簡書作者)
原文連結:http://www.jianshu.com/p/9368ce9bb8f9
著作權歸作者所有,轉載請聯絡作者獲得授權,並標註“簡書作者”。