當前位置:首頁 > 新聞中心 > 常見問題
iOS常見文件及程序的啟動原理責(zé)任編輯 :李飛    文章來源 :碼農(nóng)網(wǎng)    發(fā)布時間 :2016-08-19    閱讀次數(shù):4962     專題 :APP制作

一. iOS中常見文件

(一). Xcode6之前

  1. 創(chuàng)建項目,默認可以看見一個存放框架的文件夾
  2. info文件以工程文件名開頭,如:第一個項目-Info.plist
  3. 項目中默認有一個PCH文件

(二). Xcode6之后(包括Xcode6)

  1. 創(chuàng)建項目,沒有框架文件夾,使用時系統(tǒng)才去加載
  2. info文件不以工程文件名開頭,如:Info.plist
  3. 項目中沒有PCH文件

(三). Info.plist文件(項目配置文件)

  1. 作用:保存應(yīng)用的信息,軟件名稱、版本號等等,相當于身份證
  2. Bundle name:程序名稱,不能超過12個字節(jié)
  3. Bundle versions string, short:APP版本號
  4. Bundle identifier:APP項目唯一標識
  5. Bundle version:內(nèi)部開發(fā)人員使用的版本號
  6. Main storyboard file base name:第一啟動的storyboard文件
  7. 注意:圖形化的Info.plist文件上面的KEY不是真實的KEY,要想看真實的KEY得看Info.plist文件的源碼
    操作:Info.plist(選中后右鍵單擊) -> Open As -> Source Code
  8. 代碼查看版本號
NSDictionary *dicInfo = [NSBundle mainBundle].infoDictionary; NSLog(@"%@",dicInfo[@"CFBundleShortVersionString"]);

(四). PCH文件

PCH文件是一個頭文件,能被項目中的其他所有源文件共享和訪問

1. PCH文件的需求

一個宏或頭文件等,很多文件都需要用到,怎么解決,搞個公用的頭文件,同時導(dǎo)入這個頭文件

2. 作用

(1). 存放一些公用的宏
(2). 存放一些公用頭文件
(3). 管理日志的輸出,自定義Log

3. 為什么要管理日志輸出

因為日志輸出非常耗性能,一般發(fā)布的時候不需要日志輸出,只有調(diào)試的時候才需要

/*
...表示能接收任何參數(shù)
__VA_ARGS__ 表示左邊...的參數(shù)會替代到右邊NSLog中
*/ #ifdef DEBUG // 調(diào)試階段 #define HMLog(...)  NSLog(__VA_ARGS__) #else // 發(fā)布階段 #define HMLog(...) #endif

5. 注意

在PCH中寫有關(guān)OC的語法,最好放在 #ifdef __OBJC__ 中,Xcode在每個OC文件中都定義了這個宏,也就意味著只有OC中的文件才擁有這些宏,避免了項目中有C文件的時候報錯。

二. 程序的啟動原理

(一). 程序的啟動過程

  1. 打開程序
  2. 執(zhí)行main函數(shù)
  3. 結(jié)束程序

(二). 執(zhí)行main函數(shù)

int main(int argc, char * argv[]) { @autoreleasepool { // 第三個參數(shù)為nil時,默認是UIApplication類名  return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

1. UIApplicationMain函數(shù)的原型

UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);

2. UIApplicationMain的底層實現(xiàn)

(1). 根據(jù)principalClassName提供的類名,創(chuàng)建一個UIApplication對象

a. UIApplication代表一個應(yīng)用程序

b. UIApplication一般用來做一些應(yīng)用級別的操作(app的提醒框,聯(lián)網(wǎng)狀態(tài),打電話,打開網(wǎng)頁,控制狀態(tài)欄)

(2). 根據(jù)delegateClassName提供的類名,創(chuàng)建一個UIApplication的代理對象

a. 程序加載完畢時調(diào)用:application:didFinishLaunchingWithOptions:

b. 程序獲取焦點時調(diào)用:applicationDidBecomeActive:

c. 程序進入后臺時調(diào)用:applicationDidEnterBackground:

d. 程序失去焦點時調(diào)用:applicationWillResignActive:

e. 程序從后臺回到前臺時調(diào)用:applicationWillEnterForeground:

f. 內(nèi)存警告,可能要終止程序時調(diào)用:applicationDidReceiveMemoryWarning:

g. 程序即將退出時調(diào)用:applicationWillTerminate:

(3). 開啟一個主運行循環(huán),它是保持程序一直在運行,并處理事件

(4). 加載Info.plist和啟動圖片,并且判斷Info.plis有沒有指定Main.storyboard,如果指定,就去加載

3. application隱藏狀態(tài)欄

a. 設(shè)置Info.plist文件:添加健View controller-based status bar appearance,設(shè)置值為NO

b. 創(chuàng)建application

c. 調(diào)用隱藏狀態(tài)欄方法

4. 補充:反射機制

反射機制好處:如果類名用字符串表示,即使類名寫錯,編譯器不報錯;如果通過反射機制,類名寫錯,編譯器報錯

NSString *class = NSStringFromClass([AppDelegate class]);
AppDelegate *strClass = NSClassFromString(@"AppDelegate");

(三). 加載Main.storyboard

1. 加載Main.storyboard步驟

a. 創(chuàng)建窗口

b. 加載Main.storyboard,并且加載Main.storyboard指定的控制器

c. 把新的控制器作為窗口的根控制器,并讓窗口顯示出來

2. 窗口(UIWindow)

a. UIWindow是一個特殊的UIView,在一個APP中一般都會有一個UIWindows,但不僅只有一個,如:軟鍵盤也是一個窗口

b. APP程序啟動完畢后,創(chuàng)建的第一個視圖控件是UIWindow,接著創(chuàng)建控制器的View,最后將控制器的view添加到UIWindow上,于是控制器的view就顯示在屏幕上

c. 一個APP之所以能顯示到屏幕上,完全是因為有UIWindow

d. UIScreen : 標識物理的屏幕,它連接著設(shè)備

e. UIWindow : 用于提供屏幕繪制支持的,提供了一些繪圖的方法

f. UIView : 窗口上有很多View,是用于提供繪圖操作的,把畫好的View添加到窗口上,就可以顯示;屏幕上的東西都是繪制上去的,刷新一遍相當于重新繪制一遍

g. 只有加載Main.storyboard的時候才創(chuàng)建窗口(這里說的加載是系統(tǒng)自動加載)

h. 如果是自己代碼加載Main.storyboard,需要自己代碼創(chuàng)建窗口

3. 補充

a. 如果把新創(chuàng)建的控制器的View用addSubview:方法直接添加到窗口上,不會有旋轉(zhuǎn)功能

b.設(shè)置窗口的根控制器rootViewController,會自動把控制器的View添加到窗口

c. 查看主窗口:application.keyWindow

d. 顯示窗口:self.window.hidden = NO;

e. 查看程序的所有窗口:application.Windows

4. addSubView和rootViewController的區(qū)別

a. 直接用addSubView,控制器會被釋放,控制器就不能處理事件

b. 直接用addSubView,控制器的view不會自動旋轉(zhuǎn)

c. 用rootViewController,控制器不會被釋放,而且控制器的view會自動旋轉(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. 注意:雖然底層會做上面兩步,但不一定是上面的代碼

6. 窗口的層級

windowLevel: UIWindowLevelNormal < UIWindowLevelStatusBar < UIWindowLevelAlert

UIWindowLevelNormal : 默認窗口的層級

UIWindowLevelStatusBar : 狀態(tài)欄、鍵盤

UIWindowLevelAlert :UIActionSheet,UIAlearView

把window的層級設(shè)置為UIWindowLevelAlert ,就會顯示在最前面

相同層級的窗口,想讓其中一個顯示,可以用那個窗口的層級加上一個數(shù)

7. 代碼模仿storyboard的加載

注:要習(xí)慣代碼創(chuàng)建窗口和控制器,因為開發(fā)中很少用到storyboard直接開發(fā),老項目中沒有storyboard

  // 創(chuàng)建窗口 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; // 加載storyboard // Main.storyboard文件名不用寫后綴 // 當寫nil時,系統(tǒng)默認[NSBundle mainBundle] UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; //創(chuàng)建控制器 //方式1:代碼創(chuàng)建控制器 //UIViewController *vc = [[UIViewController alloc] init]; //vc.view.backgroundColor = [UIColor whiteColor]; //方式2:加載storyboard里面有箭頭的控制器 //UIViewController *vc = [storyboard instantiateInitialViewController]; // 當加載storyboard里面的控制器,控制器所屬哪個類,就是創(chuàng)建哪個類 //NSLog(@"%@",NSStringFromClass([vc class])); //方式3:storyboard里面有多個控制器,加載對應(yīng)標識的控制器 UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"B"]; //創(chuàng)建窗口的根控制器 self.window.rootViewController = vc; // 顯示窗口 [self.window makeKeyAndVisible];

(四). 通過XIB創(chuàng)建控制器的view

1. 步驟

a. 創(chuàng)建一個控制器的類

b. 創(chuàng)建一個xib,并指定xib所描述的控制器,一個xib只能用來描述一個控制器,如果沒有指定,就不能拖線指定控制器的view

注意:xib里可以有多個UIView,不能固定死

這里寫圖片描述

c. 拖線指定xib中哪個UIView是控制器的view

選中File`s Owner,右鍵單擊后,在彈出的對話框上拖線

這里寫圖片描述

這里寫圖片描述

d. 代碼加載xib中描述控制器的view

  //創(chuàng)建窗口 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; // 方式一:明確initWithNibName:方法的兩個參數(shù) //UIViewController *vc = [[ViewController alloc] initWithNibName:@"View" bundle:[NSBundle mainBundle]]; // 方式二:initWithNibName:方法的兩個參數(shù),只明確第一個參數(shù),省略第二個參數(shù) // bundle寫nil時,系統(tǒng)默認[NSBundle mainBundle] //UIViewController *vc = [[ViewController alloc] initWithNibName:@"View" bundle:nil]; // 方式三:initWithNibName:方法的兩個參數(shù)都省略 //UIViewController *vc = [[ViewController alloc] initWithNibName:nil bundle:nil]; // 方式四:調(diào)用init方法 UIViewController *vc = [[ViewController alloc] init]; // 設(shè)置窗口的根控制器 self.window.rootViewController = vc; // 設(shè)置程序的主窗口并顯示窗口 [self.window makeKeyAndVisible];

2. 注意

只有控制器的init方法,底層才會調(diào)用initWithNibName:bundle:方法

3. view的創(chuàng)建

這里寫圖片描述

a. 如果重寫loadView,就根據(jù)自定義的view創(chuàng)建view

b. 如果沒有重寫loadView,就去查看有沒有storyboard,有storyboard,就根據(jù)storyboard里描述的view創(chuàng)建;

c. 如果沒有storyboard,就去查看有沒有指定的xib,有指定的xib,就根據(jù)xib里描述的view創(chuàng)建;

d. 如果沒有指定的xib,即nibName為nil時,就查看有沒有與xib的擁有者同名的xib,但優(yōu)選查看沒有Controller的xib,如果查不到,就查看有沒有與xib的擁有者完全同名的xib,如:xib的擁有者是ViewController,xib的文件名是View,就優(yōu)先查看View.xib,根據(jù)它描述的view創(chuàng)建;如果沒有文件名為View的xib,就去查看有沒有名字為ViewController的xib,如果有就根據(jù)xib里描述的view創(chuàng)建

e. 如果以上的情況都沒有,就創(chuàng)建一個空的View

4. 控制器的loadView方法

A. loadView的作用:自定義控制器的view,只要重寫了這個方法,說明要自己創(chuàng)建view,就不會自動創(chuàng)建view

B. loadView什么時候調(diào)用:第一次使用view的時候調(diào)用,調(diào)用這個方法創(chuàng)建控制器的view。

C. loadView默認做法:如果storyboard描述了控制器的view,就會去加載storyboard的view

D. 注意:

a. 只要重寫loadView方法,沒有調(diào)用系統(tǒng)默認的做法,即不寫[super loadView],就不會去加載storyboard或者xib來描述控制器的view

b. 如果重寫loadView方法,并且指定了nibName,loadView默認的做法會去加載xib的view

c. 只要重寫loadView方法,沒有指定nibName,就不會自動去加載和控制器同名的xib

d. 在重寫loadView時,沒有給self.view創(chuàng)建view,就使用self.view,會造成死循環(huán)

e. 如果是根控制器的view,自定義view的時候可以不設(shè)置尺寸,系統(tǒng)會自動設(shè)置;不是跟控制器就不行;可以用CGRctZeco表示,如:self.view = [[UIView alloc] initWithFrame: CGRctZeco];

f. 重寫loadView方法時,不要寫[super loadView];,因為重寫該方法的目的是自定義view,重寫了還要去加載storyboard里的view,
等于多此一舉

5. xib和storyboard的區(qū)別

storyboard已經(jīng)指定了控制器的view,不需要我們管,xib需要我們手動管理

6. 如何快速生成一個xib描述控制器的view

  1. 定義新的控制器的時候,勾選xib,會自動搞一個xib描述控制器的view
  2. 會自動生成一個和控制器同名的xib,并且里面設(shè)置好了

(五). 控制器的View

1. view的生命周期

只要是View開頭的都是View的生命周期方法

這里寫圖片描述

loadView:第一次使用view的時候調(diào)用

viewDidLoad:控制器的view加載完成的時候調(diào)用

viewWillAppear:控制器的view即將顯示的時候調(diào)用

viewDidAppear:控制器的view完全顯示的時候調(diào)用

viewWillDisappear:控制器的view即將消失的時候調(diào)用

viewDidDisappear:控制器的view完全消失的時候調(diào)用

viewWillLayoutSubviews:控制器的view即將布局的時候調(diào)用

viewDidLayoutSubviews:控制器的view完全布局的時候調(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)存警告處理時,ViewWillUnload和ViewDidUnload不一定被調(diào)用,因為這是系統(tǒng)自動判斷的


文章轉(zhuǎn)載請保留網(wǎng)址:http://16qt59sf.cn/news/faq/1748.html

掃碼添加微信
159 8667 8737
24小時電話

返回頂部