iOS 常見文件及程序的啟動(dòng)原理

一、PCH 文件
PCH 是一個(gè)頭文件,能被項(xiàng)目中的所有源文件共享和訪問。

  1. PCH 文件的需求
    一個(gè)宏或者頭文件等,很多文件都需要用到,怎么解決,搞個(gè)共用的頭文件,同時(shí)導(dǎo)入這個(gè)頭文件。
  2. 作用
    a. 存放一些共用的宏
    b. 存放一些共用的頭文件
    c. 管理日志的輸入,自定義LOG
  3. 為什么要管理日志輸出
    因?yàn)槿罩据敵龇浅:男阅?,一般發(fā)布的時(shí)候不需要日志輸出,只有調(diào)試的時(shí)候才需要。
  4. 注意
    在PCH 中寫有關(guān)OC的方法,最好放在#ifdef OBJC中,xcode 在每個(gè)OC文件中都定義了這個(gè)宏,也就意味著只有OC文件才擁有這些宏,避免了項(xiàng)目文件中有C文件報(bào)錯(cuò)。

二、程序啟動(dòng)原理

  1. 程序啟動(dòng)過程
    a. 打開程序
    b. 執(zhí)行main 函數(shù)
    c. 結(jié)束程序
  2. 執(zhí)行Main 函數(shù)
    a. UIApplicationMian 函數(shù)原型:UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString * __nullable principalClassName, NSString * __nullable delegateClassName);
    b. UIApplicationMian 的底層實(shí)現(xiàn):
    (1). 根據(jù)principalClassName 提供的類名,創(chuàng)建一個(gè)UIApplication 對(duì)象。
    1. UIApplication 代表一個(gè)應(yīng)用程序
    2. UIApplication 一般用來做一些應(yīng)用級(jí)別的操作(app 的提醒框,聯(lián)網(wǎng)狀態(tài),打電話,打開網(wǎng)頁(yè),控制狀態(tài))
      (2). 根據(jù)delegateClassName 提供的類名,創(chuàng)建一個(gè)UIApplication 對(duì)象。
    3. 程序加載完畢時(shí)調(diào)用:application:didFinishLaunchingWithOptions:
    4. 程序獲取焦點(diǎn)時(shí)調(diào)用:applicationDidBecomeActive:
    5. 程序進(jìn)入后臺(tái)時(shí)調(diào)用:applicationDidEnterBackgroup:
    6. 程序失去焦點(diǎn)時(shí)調(diào)用:applicationWillResignActive:
    7. 程序從后臺(tái)進(jìn)入前臺(tái)時(shí)調(diào)用:applicationWillEnterForegroup:
    8. 內(nèi)存警告,可能要終止程序時(shí)調(diào)用:applicationDidReceviceMemoryWarning:
    9. 程序即將退出時(shí)調(diào)用:applicationWillTerminate:
      (3). 開啟一個(gè)主運(yùn)行循環(huán),它是保存程序一直運(yùn)行,并處理事件。
      (4). 加載info.plist 和啟動(dòng)圖片,并且判斷info.plist 有沒有指定Main.storyboard,如果指定就去加載。
  3. application 隱藏狀態(tài)欄
    (1). 設(shè)置Info.plist文件:添加健View controller-based status bar appearance,設(shè)置值為NO。
    (2). 創(chuàng)建application。
    (3). 調(diào)用隱藏狀態(tài)欄的方法。
  4. 補(bǔ)充:反射機(jī)制
    反射機(jī)制的好處:如果類名用字符串表示,即使類名寫錯(cuò)了,編輯器不會(huì)報(bào)錯(cuò);通過反射機(jī)制類名寫錯(cuò)了,編譯器報(bào)錯(cuò)。
    NSString * class = NSStringFromClass([AppDelegate class]);
    appDelegate * strClass = NSClassFromString(@"AppDelegate");

三、加載Main.storyboard

  1. 加載Main.storyboard 步驟
    a. 創(chuàng)建窗口
    b. 加載Main.storyboard,并且加載Main.storyboard指定的控制器
    c. 把新的控制器作為窗口的根控制器,并讓窗口顯示出來
  2. 窗口Window
    a. UIWindow 是一個(gè)特殊的UIView, 在一個(gè)app 中一般都會(huì)有一個(gè)UIWindow ,但不僅只有一個(gè),例如:鍵盤也是一個(gè)窗口
    b. app 程序啟動(dòng)完成后,創(chuàng)建的第一個(gè)視圖控件就是UIWindow, 接著創(chuàng)建控制器的UIView,最后將控制器添加到Window上,于是控制器的view 就顯示在屏幕上了。
    c. 一個(gè)app 之所以能顯示在屏幕上,完全是因?yàn)橛蠻IWindow。
    d. UIScreen :標(biāo)識(shí)物理的屏幕,他連接著設(shè)備。
    e. UIWindow :用于提供繪制支持,提供了一些繪制方法。
    f. UIView :窗口上有很多view,是用于繪圖操作的,把畫好的view 添加到窗口上;屏幕上的東西都是繪制上去的,刷新一遍相當(dāng)于重新繪制一遍。
    g. 只有加載Main.storyborad 的時(shí)候才創(chuàng)建窗口(加載:系統(tǒng)自動(dòng)加載)
    h. 如果是自己用代碼加載Main.storyborad 需要自己創(chuàng)建窗口代碼。
  3. 補(bǔ)充
    a. 如果把新建的控制器的view用addSubview: 方法直接添加到窗口上,不會(huì)有旋轉(zhuǎn)功能。
    b. 設(shè)置窗口的根視圖控制器RootViewController,會(huì)自動(dòng)把控制器的view添加到窗口。
    c. 查看主窗口:application.keyWindow
    d. 顯示窗口:self.window.hidden = NO
    e. 查看程序的所有窗口:application.windows
  4. addSubView 和rootViewController 的區(qū)別
    a. 直接用addSubView,控制器會(huì)被釋放,控制器就不能處理事件。
    b. 直接用addSubView,控制器的view不會(huì)旋轉(zhuǎn)。
    c. 用rootViewController,控制器不會(huì)被釋放,而且控制器的view會(huì)自動(dòng)旋轉(zhuǎn)。
    d. 旋轉(zhuǎn)事件->UIApplication -> window -> rootViewController -> 旋轉(zhuǎn)控制器view
  5. makeKeyAndVisible 方法底層做的事
    a. 把窗口設(shè)置成主窗口,如:application.keyWindow = self.window;
    b. 顯示窗口,如:self.window.hidden = NO;
    c. 注意:雖然底層會(huì)做上面兩步,但不一定是上面的代碼。
  6. 窗口的層級(jí)
    a. windowLevel: UIWindowLevelNormal < UIWindowLevelStatusBar < UIWindowLevelAlert
    b. UIWindowLevelNormal :默認(rèn)頂層層級(jí)
    c. UIWindowLevelStatusBar :狀態(tài)欄、鍵盤
    d. UIWindowLevelAlert:UIAlertView 、UIActionSheet
    e. 把window 的層級(jí)設(shè)置成UIWindowLevelAlert ,就會(huì)顯示在最前面了。
    f. 相同層級(jí)的窗口,想讓其中一個(gè)顯示,可以用那個(gè)窗口的層級(jí)加上一個(gè)數(shù)
  7. 代碼模仿main.storyboard 加載
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"main" bundle:nil];
    UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:@"B"]
    self.window.rootViewController = vc;

四、通過XIB 創(chuàng)建控制器的View

  1. 步驟
    a. 創(chuàng)建一個(gè)控制器類
    b. 創(chuàng)建一個(gè)xib,并指定所描述的控制器,一個(gè)xib 只能用來描述一個(gè)控制器,如果沒有指定,就不能拖線指定控制器的view
    c. 拖線指定xib 中的哪個(gè)UIView 是控制器的view
  2. 只有控制器的init 的方法,底層才會(huì)調(diào)用initWithNibName:bundle:方法
  3. UIView 的創(chuàng)建
    a. 如果重寫loadView ,就根據(jù)自定義view 去創(chuàng)建view
    b. 如果沒有重寫loadView,就去查看有沒有storyboard,有storyboard,就根據(jù)storyboard 描述的view去創(chuàng)建
    c. 如果沒有storyboard 就去看是否 有對(duì)于的XIB,有xib 就根據(jù)xib 的描述的view創(chuàng)建
    d. 如果沒有xib, 即nibName == nil 時(shí),就查有沒有同名的xib,但是優(yōu)先查看沒有controller 的xib, 如果查不到與xib完全同名的xib,如:xib的擁有者是viewController ,xib 的文件名就是view,就優(yōu)先查view.xib,根據(jù)它的描述的view創(chuàng)建;如果沒有文件名的xib,就去查看名字為ViewController 的xib, 如果有就根據(jù)xib 里的描述的view 創(chuàng)建
  4. 控制器的loadView方法
    a. loadView的作用:自定義控制器view, 只要重寫這個(gè)方法,說明要?jiǎng)?chuàng)建view,就不會(huì)自動(dòng)創(chuàng)建view
    b. loadView 說明時(shí)候調(diào)用:第一次使用view的時(shí)候調(diào)用,調(diào)用這個(gè)方法創(chuàng)建控制器的view
    c. loadView 默認(rèn)做法:如果storyboard 描述了控制器view,就去加載
    d. 注意:1.只要重寫loadView方法,沒有調(diào)用系統(tǒng)默認(rèn)的做法,即不寫[super loadView],就不會(huì)去加載storyboard或者xib來描述控制器的view 2.如果重寫loadView方法,并且指定了nibName,loadView默認(rèn)的做法會(huì)去加載xib的view 3. 只要重寫loadView方法,沒有指定nibName,就不會(huì)自動(dòng)去加載和控制器同名的xib 4. 在重寫loadView時(shí),沒有給self.view創(chuàng)建view,就使用self.view,會(huì)造成死循環(huán) 5. 如果是根控制器的view,自定義view的時(shí)候可以不設(shè)置尺寸,系統(tǒng)會(huì)自動(dòng)設(shè)置;不是跟控制器就不行;可以用CGRctZeco表示,如:self.view = [[UIView alloc] initWithFrame: CGRctZeco]; 6. 重寫loadView方法時(shí),不要寫[super loadView];,因?yàn)橹貙懺摲椒ǖ哪康氖亲远xview,重寫了還要去加載storyboard里的view,等于多此一舉
  5. xib 和storyboard 的區(qū)別
    storyboard 已經(jīng)指定了控制器view,不需要我們管,xib 需要我們手動(dòng)管理。
  6. 如何快速生成一個(gè)xib 描述的控制器view
    1、定義新的控制器的時(shí)候,勾選xib,會(huì)自動(dòng)搞一個(gè)xib描述控制器的view
    2、會(huì)自動(dòng)生成一個(gè)和控制器同名的xib,并且里面設(shè)置好了

五、控制器view

  1. view的生命周期:只要是view開頭的都是view的生命周期方法
    loadView:第一次使用view的時(shí)候調(diào)用
    viewDidLoad:控制器的view加載完成的時(shí)候調(diào)用
    viewWillAppear:控制器的view即將顯示的時(shí)候調(diào)用
    viewDidAppear:控制器的view完全顯示的時(shí)候調(diào)用
    viewWillDisappear:控制器的view即將消失的時(shí)候調(diào)用
    viewDidDisappear:控制器的view完全消失的時(shí)候調(diào)用
    viewWillLayoutSubviews:控制器的view即將布局的時(shí)候調(diào)用
    viewDidLayoutSubviews:控制器的view完全布局的時(shí)候調(diào)用
    viewWillUnload:控制器的view即將銷毀
    viewDidUnload:控制器的view完全銷毀
  2. 內(nèi)存警告處理
    a、處理過程

有內(nèi)存警告 -> 調(diào)用didReceiveMemoryWarning方法 -> 判斷控制器的View存不
存在 ->
存在就判斷能不能被釋放(判斷是不是正在顯示在界面上) -> 能釋放就調(diào)用ViewWillUnload ->
完全釋放后就調(diào)用ViewDidUnload

b、注意

內(nèi)存警告處理時(shí),ViewWillUnload和ViewDidUnload不一定被調(diào)用,因?yàn)檫@是系統(tǒng)自動(dòng)判斷的

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容