iOS常見檔案及程式的啟動原理
一. iOS中常見檔案
(一). Xcode6之前
- 建立專案,預設可以看見一個存放框架的資料夾
- info檔案以工程檔名開頭,如:第一個專案-Info.plist
- 專案中預設有一個PCH檔案
(二). Xcode6之後(包括Xcode6)
- 建立專案,沒有框架資料夾,使用時系統才去載入
- info檔案不以工程檔名開頭,如:Info.plist
- 專案中沒有PCH檔案
(三). Info.plist檔案(專案配置檔案)
- 作用:儲存應用的資訊,軟體名稱、版本號等等,相當於身份證
- Bundle name:程式名稱,不能超過12個位元組
- Bundle versions string, short:APP版本號
- Bundle identifier:APP專案唯一標識
- Bundle version:內部開發人員使用的版本號
- Main storyboard file base name:第一啟動的storyboard檔案
- 注意:圖形化的Info.plist檔案上面的KEY不是真實的KEY,要想看真實的KEY得看Info.plist檔案的原始碼
操作:Info.plist(選中後右鍵單擊) -> Open As -> Source Code - 程式碼檢視版本號
NSDictionary *dicInfo = [NSBundle mainBundle].infoDictionary; NSLog(@"%@",dicInfo[@"CFBundleShortVersionString"]);
(四). PCH檔案
PCH檔案是一個標頭檔案,能被專案中的其他所有原始檔共享和訪問
1. PCH檔案的需求
一個巨集或標頭檔案等,很多檔案都需要用到,怎麼解決,搞個公用的標頭檔案,同時匯入這個標頭檔案
2. 作用
(1). 存放一些公用的巨集
(2). 存放一些公用標頭檔案
(3). 管理日誌的輸出,自定義Log
3. 為什麼要管理日誌輸出
因為日誌輸出非常耗效能,一般釋出的時候不需要日誌輸出,只有除錯的時候才需要
/* ...表示能接收任何引數 __VA_ARGS__ 表示左邊...的引數會替代到右邊NSLog中 */ #ifdef DEBUG // 除錯階段 #define HMLog(...) NSLog(__VA_ARGS__) #else // 釋出階段 #define HMLog(...) #endif
5. 注意
在PCH中寫有關OC的語法,最好放在 #ifdef __OBJC__ 中,Xcode在每個OC檔案中都定義了這個巨集,也就意味著只有OC中的檔案才擁有這些巨集,避免了專案中有C檔案的時候報錯。
二. 程式的啟動原理
(一). 程式的啟動過程
- 開啟程式
- 執行main函式
- 結束程式
(二). 執行main函式
int main(int argc, char * argv[]) { @autoreleasepool { // 第三個引數為nil時,預設是UIApplication類名 return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
1. UIApplicationMain函式的原型
UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
2. UIApplicationMain的底層實現
(1). 根據principalClassName提供的類名,建立一個UIApplication物件
a. UIApplication代表一個應用程式
b. UIApplication一般用來做一些應用級別的操作(app的提醒框,聯網狀態,打電話,開啟網頁,控制狀態列)
(2). 根據delegateClassName提供的類名,建立一個UIApplication的代理物件
a. 程式載入完畢時呼叫:application:didFinishLaunchingWithOptions:
b. 程式獲取焦點時呼叫:applicationDidBecomeActive:
c. 程式進入後臺時呼叫:applicationDidEnterBackground:
d. 程式失去焦點時呼叫:applicationWillResignActive:
e. 程式從後臺回到前臺時呼叫:applicationWillEnterForeground:
f. 記憶體警告,可能要終止程式時呼叫:applicationDidReceiveMemoryWarning:
g. 程式即將退出時呼叫:applicationWillTerminate:
(3). 開啟一個主執行迴圈,它是保持程式一直在執行,並處理事件
(4). 載入Info.plist和啟動圖片,並且判斷Info.plis有沒有指定Main.storyboard,如果指定,就去載入
3. application隱藏狀態列
a. 設定Info.plist檔案:新增健View controller-based status bar appearance,設定值為NO
b. 建立application
c. 呼叫隱藏狀態列方法
4. 補充:反射機制
反射機制好處:如果類名用字串表示,即使類名寫錯,編譯器不報錯;如果通過反射機制,類名寫錯,編譯器報錯
NSString *class = NSStringFromClass([AppDelegate class]); AppDelegate *strClass = NSClassFromString(@"AppDelegate");
(三). 載入Main.storyboard
1. 載入Main.storyboard步驟
a. 建立視窗
b. 載入Main.storyboard,並且載入Main.storyboard指定的控制器
c. 把新的控制器作為視窗的根控制器,並讓視窗顯示出來
2. 視窗(UIWindow)
a. UIWindow是一個特殊的UIView,在一個APP中一般都會有一個UIWindows,但不僅只有一個,如:軟鍵盤也是一個視窗
b. APP程式啟動完畢後,建立的第一個檢視控制元件是UIWindow,接著建立控制器的View,最後將控制器的view新增到UIWindow上,於是控制器的view就顯示在螢幕上
c. 一個APP之所以能顯示到螢幕上,完全是因為有UIWindow
d. UIScreen : 標識物理的螢幕,它連線著裝置
e. UIWindow : 用於提供螢幕繪製支援的,提供了一些繪圖的方法
f. UIView : 視窗上有很多View,是用於提供繪圖操作的,把畫好的View新增到視窗上,就可以顯示;螢幕上的東西都是繪製上去的,重新整理一遍相當於重新繪製一遍
g. 只有載入Main.storyboard的時候才建立視窗(這裡說的載入是系統自動載入)
h. 如果是自己程式碼載入Main.storyboard,需要自己程式碼建立視窗
3. 補充
a. 如果把新建立的控制器的View用addSubview:方法直接新增到視窗上,不會有旋轉功能
b.設定視窗的根控制器rootViewController,會自動把控制器的View新增到視窗
c. 檢視主視窗:application.keyWindow
d. 顯示視窗:self.window.hidden = NO;
e. 檢視程式的所有視窗:application.Windows
4. addSubView和rootViewController的區別
a. 直接用addSubView,控制器會被釋放,控制器就不能處理事件
b. 直接用addSubView,控制器的view不會自動旋轉
c. 用rootViewController,控制器不會被釋放,而且控制器的view會自動旋轉
d. 旋轉事件 -> UIApplication -> Window -> rootViewController ->旋轉控制器的view
5. makeKeyAndVisible方法底層所做的事情
a. 把視窗設定成主視窗,如:application.keyWindow = self.window;
b. 顯示視窗,如:self.window.hidden = NO;
c. 注意:雖然底層會做上面兩步,但不一定是上面的程式碼
6. 視窗的層級
windowLevel: UIWindowLevelNormal < UIWindowLevelStatusBar < UIWindowLevelAlert
UIWindowLevelNormal : 預設視窗的層級
UIWindowLevelStatusBar : 狀態列、鍵盤
UIWindowLevelAlert :UIActionSheet,UIAlearView
把window的層級設定為UIWindowLevelAlert ,就會顯示在最前面
相同層級的視窗,想讓其中一個顯示,可以用那個視窗的層級加上一個數
7. 程式碼模仿storyboard的載入
注:要習慣程式碼建立視窗和控制器,因為開發中很少用到storyboard直接開發,老專案中沒有storyboard
// 建立視窗 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; // 載入storyboard // Main.storyboard檔名不用寫字尾 // 當寫nil時,系統預設[NSBundle mainBundle] UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; //建立控制器 //方式1:程式碼建立控制器 //UIViewController *vc = [[UIViewController alloc] init]; //vc.view.backgroundColor = [UIColor whiteColor]; //方式2:載入storyboard裡面有箭頭的控制器 //UIViewController *vc = [storyboard instantiateInitialViewController]; // 當載入storyboard裡面的控制器,控制器所屬哪個類,就是建立哪個類 //NSLog(@"%@",NSStringFromClass([vc class])); //方式3:storyboard裡面有多個控制器,載入對應標識的控制器 UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"B"]; //建立視窗的根控制器 self.window.rootViewController = vc; // 顯示視窗 [self.window makeKeyAndVisible];
(四). 通過XIB建立控制器的view
1. 步驟
a. 建立一個控制器的類
b. 建立一個xib,並指定xib所描述的控制器,一個xib只能用來描述一個控制器,如果沒有指定,就不能拖線指定控制器的view
注意:xib裡可以有多個UIView,不能固定死
c. 拖線指定xib中哪個UIView是控制器的view
選中File`s Owner,右鍵單擊後,在彈出的對話方塊上拖線
d. 程式碼載入xib中描述控制器的view
//建立視窗 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; // 方式一:明確initWithNibName:方法的兩個引數 //UIViewController *vc = [[ViewController alloc] initWithNibName:@"View" bundle:[NSBundle mainBundle]]; // 方式二:initWithNibName:方法的兩個引數,只明確第一個引數,省略第二個引數 // bundle寫nil時,系統預設[NSBundle mainBundle] //UIViewController *vc = [[ViewController alloc] initWithNibName:@"View" bundle:nil]; // 方式三:initWithNibName:方法的兩個引數都省略 //UIViewController *vc = [[ViewController alloc] initWithNibName:nil bundle:nil]; // 方式四:呼叫init方法 UIViewController *vc = [[ViewController alloc] init]; // 設定視窗的根控制器 self.window.rootViewController = vc; // 設定程式的主視窗並顯示視窗 [self.window makeKeyAndVisible];
2. 注意
只有控制器的init方法,底層才會呼叫initWithNibName:bundle:方法
3. view的建立
a. 如果重寫loadView,就根據自定義的view建立view
b. 如果沒有重寫loadView,就去檢視有沒有storyboard,有storyboard,就根據storyboard裡描述的view建立;
c. 如果沒有storyboard,就去檢視有沒有指定的xib,有指定的xib,就根據xib裡描述的view建立;
d. 如果沒有指定的xib,即nibName為nil時,就檢視有沒有與xib的擁有者同名的xib,但優選檢視沒有Controller的xib,如果查不到,就檢視有沒有與xib的擁有者完全同名的xib,如:xib的擁有者是ViewController,xib的檔名是View,就優先檢視View.xib,根據它描述的view建立;如果沒有檔名為View的xib,就去檢視有沒有名字為ViewController的xib,如果有就根據xib裡描述的view建立
e. 如果以上的情況都沒有,就建立一個空的View
4. 控制器的loadView方法
A. loadView的作用:自定義控制器的view,只要重寫了這個方法,說明要自己建立view,就不會自動建立view
B. loadView什麼時候呼叫:第一次使用view的時候呼叫,呼叫這個方法建立控制器的view。
C. loadView預設做法:如果storyboard描述了控制器的view,就會去載入storyboard的view
D. 注意:
a. 只要重寫loadView方法,沒有呼叫系統預設的做法,即不寫[super loadView],就不會去載入storyboard或者xib來描述控制器的view b. 如果重寫loadView方法,並且指定了nibName,loadView預設的做法會去載入xib的view c. 只要重寫loadView方法,沒有指定nibName,就不會自動去載入和控制器同名的xib d. 在重寫loadView時,沒有給self.view建立view,就使用self.view,會造成死迴圈 e. 如果是根控制器的view,自定義view的時候可以不設定尺寸,系統會自動設定;不是跟控制器就不行;可以用CGRctZeco表示,如:self.view = [[UIView alloc] initWithFrame: CGRctZeco]; f. 重寫loadView方法時,不要寫[super loadView];,因為重寫該方法的目的是自定義view,重寫了還要去載入storyboard裡的view, 等於多此一舉
5. xib和storyboard的區別
storyboard已經指定了控制器的view,不需要我們管,xib需要我們手動管理
6. 如何快速生成一個xib描述控制器的view
- 定義新的控制器的時候,勾選xib,會自動搞一個xib描述控制器的view
- 會自動生成一個和控制器同名的xib,並且裡面設定好了
(五). 控制器的View
1. view的生命週期
只要是View開頭的都是View的生命週期方法
loadView:第一次使用view的時候呼叫
viewDidLoad:控制器的view載入完成的時候呼叫
viewWillAppear:控制器的view即將顯示的時候呼叫
viewDidAppear:控制器的view完全顯示的時候呼叫
viewWillDisappear:控制器的view即將消失的時候呼叫
viewDidDisappear:控制器的view完全消失的時候呼叫
viewWillLayoutSubviews:控制器的view即將佈局的時候呼叫
viewDidLayoutSubviews:控制器的view完全佈局的時候呼叫
viewWillUnload:控制器的view即將銷燬
viewDidUnload:控制器的view完全銷燬
2. 記憶體警告處理
a. 處理過程
有記憶體警告 -> 呼叫didReceiveMemoryWarning方法 -> 判斷控制器的View存不存在 -> 存在就判斷能不能被釋放(判斷是不是正在顯示在介面上) -> 能釋放就呼叫ViewWillUnload -> 完全釋放後就呼叫ViewDidUnload
b. 注意
記憶體警告處理時,ViewWillUnload和ViewDidUnload不一定被呼叫,因為這是系統自動判斷的
相關文章
- iOS加固原理與常見措施:保護移動應用程式安全的利器iOS
- 常見排序原理及 python 實現排序Python
- 常見排序演算法原理及JS程式碼實現排序演算法JS
- iOS FTPManager的簡單使用及常見問題iOSFTP
- 幾種常見取樣方法及原理
- 常見檔案MIME對照表
- python檔案的常見的操作有哪些?Python
- Linux系統常見的日誌檔案及優先順序別!Linux
- Go常見錯誤集錦 | 字串底層原理及常見錯誤Go字串
- Go 常見錯誤集錦 | 字串底層原理及常見錯誤Go字串
- 在NodeJS中操作檔案常見的APINodeJSAPI
- C#常見的檔案路徑ApiC#API
- 檔案上傳常見問題
- 【小白必學】檔案上傳的漏洞介紹及常見防禦方法
- cadence 開啟原理圖檔案
- Linux常見命令-目錄檔案命令Linux
- 常見的PID的演算法及程式碼示例演算法
- ios檔案管理軟體FoneLab FoneTrans for iOS免費安裝及啟用圖文教程iOS
- iOS常見的幾種加密方法iOS加密
- Linux系統上常見的檔案管理類命令Linux
- SSH原理常見應用升級及埠轉發
- RMI原理及常見反序列化攻擊手法
- Redis解讀(1):Redis安裝啟動及常見資料型別Redis資料型別
- Python常見檔案讀寫方法有哪些?Python
- linux的啟動配置檔案inittab檔案詳解Linux
- 檔案上傳踩坑記及檔案清理原理探究
- 程式啟動原理和UIApplicationUIAPP
- 計算機程式的思維邏輯 (64) – 常見檔案型別處理: 屬性檔案/CSV/EXCEL/HTML/壓縮檔案計算機型別ExcelHTML
- Tomcat常見異常及解決方案程式碼例項Tomcat
- react 常見setState的原理解析React
- Linux系統常見檔案大小常用的命令詳解!Linux
- Linux系統中,常見的隱形檔案有哪些?Linux
- flannel vxlan工作基本原理及常見排障方法
- Oracle RAC常見啟動失敗故障分析Oracle
- HIDS 常見檢測原理
- ORACLE OGG引數修改引起佇列檔案異常導致抽取程式無法啟動Oracle佇列
- 常見的ftp檔案傳輸工具有哪些?推薦ftp檔案傳輸工具FTP
- css在移動端常遇到的檔案CSS
- iOS 避免常見崩潰(二)iOS