創建項目,默認可以看見一個存放框架的文件夾
info文件以工程文件名開頭,如:第一個項目-Info.plist
項目中默認有一個PCH文件
創建項目,沒有框架文件夾,使用時系統才去加載
info文件不以工程文件名開頭,如:Info.plist
項目中沒有PCH文件
作用:保存應用的信息,軟件名稱、版本號等等,相當於身份證
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"]);1212
PCH文件是一個頭文件,能被項目中的其他所有源文件共享和訪問
一個宏或頭文件等,很多文件都需要用到,怎麼解決,搞個公用的頭文件,同時導入這個頭文件
(1). 存放一些公用的宏
(2). 存放一些公用頭文件
(3). 管理日志的輸出,自定義Log
因為日志輸出非常耗性能,一般發布的時候不需要日志輸出,只有調試的時候才需要
/*...表示能接收任何參數 __VA_ARGS__ 表示左邊...的參數會替代到右邊NSLog中 */#ifdef DEBUG // 調試階段#define HMLog(...) NSLog(__VA_ARGS__)#else // 發布階段#define HMLog(...)#endif123456789123456789
在PCH中寫有關OC的語法,最好放在 #ifdef __OBJC__ 中,Xcode在每個OC文件中都定義了這個宏,也就意味著只有OC中的文件才擁有這些宏,避免了項目中有C文件的時候報錯。
打開程序
執行main函數
結束程序
int main(int argc, char * argv[]) { @autoreleasepool { // 第三個參數為nil時,默認是UIApplication類名 return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }123456123456
UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);11
a. UIApplication代表一個應用程序
b. UIApplication一般用來做一些應用級別的操作(app的提醒框,聯網狀態,打電話,打開網頁,控制狀態欄)
a. 程序加載完畢時調用:application:didFinishLaunchingWithOptions:
b. 程序獲取焦點時調用:applicationDidBecomeActive:
c. 程序進入後台時調用:applicationDidEnterBackground:
d. 程序失去焦點時調用:applicationWillResignActive:
e. 程序從後台回到前台時調用:applicationWillEnterForeground:
f. 內存警告,可能要終止程序時調用:applicationDidReceiveMemoryWarning:
g. 程序即將退出時調用:applicationWillTerminate:
a. 設置Info.plist文件:添加健View controller-based status bar appearance,設置值為NO
b. 創建application
c. 調用隱藏狀態欄方法
反射機制好處:如果類名用字符串表示,即使類名寫錯,編譯器不報錯;如果通過反射機制,類名寫錯,編譯器報錯
NSString *class = NSStringFromClass([AppDelegate class]);AppDelegate *strClass = NSClassFromString(@"AppDelegate");1212
a. 創建窗口
b. 加載Main.storyboard,並且加載Main.storyboard指定的控制器
c. 把新的控制器作為窗口的根控制器,並讓窗口顯示出來
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,需要自己代碼創建窗口
a. 如果把新創建的控制器的View用addSubview:方法直接添加到窗口上,不會有旋轉功能
b.設置窗口的根控制器rootViewController,會自動把控制器的View添加到窗口
c. 查看主窗口:application.keyWindow
d. 顯示窗口:self.window.hidden = NO;
e. 查看程序的所有窗口:application.Windows
a. 直接用addSubView,控制器會被釋放,控制器就不能處理事件
b. 直接用addSubView,控制器的view不會自動旋轉
c. 用rootViewController,控制器不會被釋放,而且控制器的view會自動旋轉
d. 旋轉事件 -> UIApplication -> Window -> rootViewController ->旋轉控制器的view
a. 把窗口設置成主窗口,如:application.keyWindow = self.window;
b. 顯示窗口,如:self.window.hidden = NO;
c. 注意:雖然底層會做上面兩步,但不一定是上面的代碼
windowLevel: UIWindowLevelNormal < UIWindowLevelStatusBar < UIWindowLevelAlert
UIWindowLevelNormal : 默認窗口的層級
UIWindowLevelStatusBar : 狀態欄、鍵盤
UIWindowLevelAlert :UIActionSheet,UIAlearView
把window的層級設置為UIWindowLevelAlert ,就會顯示在最前面
相同層級的窗口,想讓其中一個顯示,可以用那個窗口的層級加上一個數
注:要習慣代碼創建窗口和控制器,因為開發中很少用到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];12345678910111213141516171819202122232425261234567891011121314151617181920212223242526
注意:xib裡可以有多個UIView,不能固定死
選中File`s Owner,右鍵單擊後,在彈出的對話框上拖線
//創建窗口 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];123456789101112131415161718123456789101112131415161718
只有控制器的init方法,底層才會調用initWithNibName:bundle:方法
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
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, 等於多此一舉
storyboard已經指定了控制器的view,不需要我們管,xib需要我們手動管理
定義新的控制器的時候,勾選xib,會自動搞一個xib描述控制器的view
會自動生成一個和控制器同名的xib,並且裡面設置好了
只要是View開頭的都是View的生命周期方法
loadView:第一次使用view的時候調用
viewDidLoad:控制器的view加載完成的時候調用
viewWillAppear:控制器的view即將顯示的時候調用
viewDidAppear:控制器的view完全顯示的時候調用
viewWillDisappear:控制器的view即將消失的時候調用
viewDidDisappear:控制器的view完全消失的時候調用
viewWillLayoutSubviews:控制器的view即將布局的時候調用
viewDidLayoutSubviews:控制器的view完全布局的時候調用
viewWillUnload:控制器的view即將銷毀
viewDidUnload:控制器的view完全銷毀
有內存警告 -> 調用didReceiveMemoryWarning方法 -> 判斷控制器的View存不存在 -> 存在就判斷能不能被釋放(判斷是不是正在顯示在界面上) -> 能釋放就調用ViewWillUnload -> 完全釋放後就調用ViewDidUnload
內存警告處理時,ViewWillUnload和ViewDidUnload不一定被調用,因為這是系統自動判斷的