1?ViewDidLoad的觸發(fā)時機(jī)(viewDidLoad)
結(jié)論:
每次訪問UIViewController的view而且view為nil拍顷,loadView方法就會被調(diào)用抚太。
系統(tǒng)是在loadView方法中創(chuàng)建好UIViewController的view的。
viewDidLoad是在loadView方法創(chuàng)建view完畢后被調(diào)用的昔案。
題外:
loadView是干嘛用的尿贫?
* loadView是手寫ViewController時,生成當(dāng)前VC視圖的惰性方法踏揣,如果要自定義View庆亡,可以直接復(fù)寫這個方法。
* 自定義的方法無需調(diào)用super方法呼伸。
2?View方法的先后順序
執(zhí)行順序:
視圖創(chuàng)建:init->viewDidLoad->viewWillAppear->viewDidAppear
視圖消失:viewWillDisappear-> viewDidDisappear
當(dāng)視圖A切換到視圖B的流程:
1、B視圖 viewDidLoad
2钝尸、A視圖 viewWillDisappear
3括享、B視圖 viewVillAppear
4、A視圖 viewDidDisappear
5珍促、B視圖 viewDidAppear
3?property
* 一類是表示原子性,有atomic和nonatomic铃辖,默認(rèn)是atomic
* 一類是表示引用計數(shù)的,有assign(unsafe_unretained),strong,weak,copy, 默認(rèn)是assign
* 一類是表示讀寫權(quán)限的,默認(rèn)是readwrite(可讀可寫)猪叙,還有就是readonly
assign與weak:共同點是都不會增加retaincount
區(qū)別是
a)assign不僅能用于基礎(chǔ)數(shù)據(jù)類型娇斩,也能用于OC對象,但weak只能用于OC對象穴翩;
b)weak是弱引用犬第,在其所引用的對象被釋放后,會將變量置為nil芒帕,不會有野指針的現(xiàn)象歉嗓。
c)weak的賦值方式是復(fù)制引用,而assign是復(fù)制數(shù)據(jù)背蟆。
d)weak只能用于ARC鉴分;
怎么用 copy 關(guān)鍵字哮幢?
* NSString、NSArray志珍、NSDictionary 等等經(jīng)常使用copy關(guān)鍵字橙垢,是因為他們有對應(yīng)的可變類型:NSMutableString、NSMutableArray伦糯、NSMutableDictionary
* block 也經(jīng)常使用 copy 關(guān)鍵字
weak實現(xiàn)原理:http://www.reibang.com/p/48044cc54392
4柜某、KVO(KVC)、Delegate舔株、NSNotification
簡介:
KVO(鍵值監(jiān)聽)莺琳,即Key-Value Observing,它提供一種機(jī)制载慈,當(dāng)指定的對象的屬性被修改后惭等,對象就會接受到通知,前提是執(zhí)行了setter方法办铡、或者使用了 KVC賦值辞做。
KVC(鍵值編碼),即Key-Value Coding寡具,一個非正式的Protocol秤茅,使用字符串(鍵)訪問一個對象實例變量的機(jī)制。而不是通過調(diào)用Setter童叠、Getter方法等 顯式的存取方式去訪問框喳。
KVO的使用:
注冊觀察者:addObserver:forKeyPath:options:context:
實現(xiàn)觀察者:observeValueForKeyPath:ofObject:change:context:
移除觀察者:removeObserver:forKeyPath:(對象銷毀,必須移除觀察者)
KVO的原理:
當(dāng)你觀察一個對象(稱該對象為「被觀察對象」)時厦坛,一個新的類會動態(tài)被創(chuàng)建(NSKVONotifying_XX)五垮。
這個類繼承自「被觀察對象」所對應(yīng)類的,并重寫該被觀察屬性的setter方法杜秸;針對setter方法的重寫無非是在賦值語句前后加上相應(yīng)的通知(或方法調(diào)用)放仗;
最后,把「被觀察對象」的isa指針(isa指針告訴Runtime系統(tǒng)這個對象的類是什么)指向這個新創(chuàng)建的中間類撬碟,對象就神奇變成了新創(chuàng)建類的實例诞挨。
雖然被觀察對象的isa指針被修改了,但是調(diào)用其class方法得到的類信息仍然是它之前所繼承類的類信息呢蛤,而不是這個新創(chuàng)建類的類信息惶傻。
友鏈:http://www.reibang.com/p/e59bb8f59302
KVO相關(guān)crash及防護(hù):
1、對不存在的屬性進(jìn)行kvo觀測
2其障、observe忘記寫監(jiān)聽回調(diào)方法 observeValueForKeyPath
3达罗、add和remove次數(shù)不匹配
4、監(jiān)聽者和被監(jiān)聽者dealloc之前沒有remove(其實也原因3,但是監(jiān)聽者和被監(jiān)聽者的生命周期不同)
方案一粮揉、
可以讓被觀察對象持有一個KVO的delegate巡李,所有和KVO相關(guān)的操作均通過delegate來進(jìn)行管理,delegate通過建立一張map來維護(hù)KVO整個關(guān)系扶认。
中間層delegate的代理工作:
(1)如果出現(xiàn)KVO重復(fù)添加觀察者或者重復(fù)移除觀察者(KVO注冊觀察者與移除觀察者不匹配)的情況侨拦,delegate可以直接阻止這些非正常的操作。
(2)被觀察者dealloc之前辐宾,可以通過delegate自動將與自己有關(guān)的KVO關(guān)系都注銷掉狱从,避免了KVO的被觀察者dealloc時仍然注冊著KVO導(dǎo)致的crash。
方案二叠纹、
我們可以讓觀察者在注冊的過程中季研,將注冊信息一同記錄下來,然后使用某種方法在對象dealloc時誉察,在記錄的信息里找到對應(yīng)的觀察者与涡,注銷觀察。
此方案在宿主釋放過程中嵌入我們自己的對象持偏,使得宿主釋放時順帶將我們的對象一起釋放掉驼卖,從而獲取dealloc的時機(jī)點。采用構(gòu)建一個釋放通知對象鸿秆,通過AssociatedObject方式連接到宿主對象酌畜,在宿主釋放時進(jìn)行回調(diào),完成注銷動作卿叽。
Delegate簡介:
代理設(shè)計模式桥胞,是iOS中一種消息傳遞的方式,由協(xié)議考婴、代理對象贩虾、委托者組成。只能一對一蕉扮。
協(xié)議(protocol):用來指定代理可以做什么整胃,必須做什么颗圣。
代理:根據(jù)指定協(xié)議喳钟,完成委托方需要實現(xiàn)的方法。
委托:根據(jù)指定協(xié)議在岂,指定代理必須完成和可以完成方法奔则。
NSNotification簡介:
NSNotificationCenter 較之于 Delegate 可以實現(xiàn)更大的跨度的通信機(jī)制,可以為兩個無引用關(guān)系的兩個對象進(jìn)行通信蔽午。NSNotification是iOS中一個調(diào)度消息通知的類易茬,采用單例模式設(shè)計。
NSNotification使用:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(xxx:) name:@"abc" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
//或者
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"abc" object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"abc" object:nil];
NSNotification相關(guān)crash及防護(hù):([https://www.cnblogs.com/Xylophone/p/6394056.html])
在退出A頁面的時候沒有把自身的通知觀察者A給注銷,導(dǎo)致通知發(fā)過來的時候拋給了一個已經(jīng)釋放的對象A抽莱,但該對象仍然被通知中心引用范抓,也就是僵尸對象,從而導(dǎo)致程序崩潰 食铐。(也就是說匕垫,在一個頁面dealloc的時候,一定要把這個頁面在通知中心remove掉虐呻,否則這個頁面很有可能成為僵尸對象)象泵。
但有兩種情況需要注意:
(1)單例里不用dealloc方法,應(yīng)用會統(tǒng)一管理斟叼;
(2)類別里不要用dealloc方法removeObserver偶惠,在類別對應(yīng)的原始類里的dealloc方法removeObserver,因為類別會調(diào)用原始類的dealloc方法朗涩。(如果在類別里新寫dealloc方法忽孽,原類里的dealloc方法就不執(zhí)行了)
方案一、
利用method swizzling hook NSObject的dealloc函數(shù)馋缅,在對象真正dealloc之前先調(diào)用一下[[NSNotificationCenter defaultCenter] removeObserver:self]即可扒腕。在其添加observer的時候,對observer動態(tài)添加標(biāo)記flag萤悴。
方案二瘾腰、
在宿主釋放過程中嵌入我們自己的對象,使得宿主釋放時順帶將我們的對象一起釋放掉覆履,從而獲取dealloc的時機(jī)點蹋盆。顯然AssociatedObject是我們想要的方案。相比Method Swizzling方案硝全,AssociatedObject方案的對工程的影響范圍小栖雾,而且只有使用自動注銷的對象才會產(chǎn)生代價。
5伟众、異常捕獲機(jī)制
Objective-C 異常機(jī)制 :
* 開發(fā)者將引發(fā)異常的代碼放在 @try 代碼塊中, 程序出現(xiàn)異常 使用 @catch 代碼塊進(jìn)行捕捉;
* @try代碼塊:存放可能出現(xiàn)異常的代碼, @catch代碼塊:異常處理邏輯, @finally代碼塊:回收資源;
* 一個@try 代碼塊可以對應(yīng)多個@catch代碼塊析藕;@try @catch @finally 的花括號不可省略;
異常處理過程
* 生成異常對象:@try 中出現(xiàn)異常, 系統(tǒng)會生成一個異常對象, 該對象提交到系統(tǒng)中,系統(tǒng)就會拋出異常
* 運行環(huán)境接收到異常對象時, 如果存在能處理該異常對象的 @catch 代碼塊, 就將該異常對象交給 @catch 處理, 該過程就是捕獲異常, 如果沒有 @catch 代碼塊處理異常, 程序就會終止
* 運行環(huán)境接收到異常對象時, 會依次判斷該異常對象類型是否是 @catch 代碼塊中異车氏幔或其子類實例, 如果匹配成功, 被匹配的 @catch 就會處理該異常, 都則就會跟下一個 @catch 代碼塊對比
try/catch能抓的異常:
NSRangeException(越界)
NSInvalidArgumentException(調(diào)用方法出錯)
NSInternalInconsistencyException(比如把NSDictionary當(dāng)做NSMutableDictionary來使用)
NSGenericException(遍歷的時候账胧,對集合進(jìn)行了插入/刪除操作)
參考:[http://www.reibang.com/p/d32778ed9dd3]
結(jié)論:
Apple雖然同時提供了錯誤處理(NSError)和異常處理(exception)兩種機(jī)制,但是Apple更加提倡開發(fā)者使用NSError來處理程序運行中可恢復(fù)的錯誤先紫。而異常被推薦用來處理不可恢復(fù)的錯誤治泥。
Exception容易造成內(nèi)存管理問題(文檔有描述即使是arc下,也不是安全的)遮精;
(try代碼塊中的對象不釋放居夹,可以用compileflags的-fobjc-arc-exceptions解決或是修改成.mm文件)
Exception使用block造成額外的開銷,效率較低等等。
6准脂、+load劫扒、+initialize的區(qū)別
* load方法是runtime在加載類后,在main函數(shù)之前狸膏,向每個類和分類發(fā)送的消息粟关,順序是父類-子類-分類. 通常在這個地方做method swizzlling或者使用Router方式做解耦的時候,通常也會在這里做URL注冊环戈;
* initialize方法是一個惰性方法闷板,被調(diào)用的前提是,該類有方法被調(diào)用院塞,如果該類一直沒有被使用過遮晚,則這個方法一直不會被調(diào)用。
相同點是拦止,兩個方法都是線程安全的县遣。
7、NSError設(shè)計成二級指針原因
為了方便回傳賦值汹族。
指針作為參數(shù)傳遞的時候萧求,指針本身是值傳遞。
在函數(shù)內(nèi)對參數(shù)指針賦值顶瞒,是不能改變原參數(shù)指針指向的值的夸政。
參考:[http://www.reibang.com/p/6a1cfef75092]
8、動畫和前后臺
現(xiàn)象:App進(jìn)入后臺時榴徐,所有動畫會在瞬間全部完成守问,但是閉包返回finish是false。
處理:
1坑资、在applicationWillEnterForeground代理方法里面重新開始所有的動畫耗帕。
2、設(shè)置animation.removedOnCompletion = NO; (屬性解釋:當(dāng)為真時袱贮,一旦活動持續(xù)時間已過仿便,動畫將從呈現(xiàn)樹中刪除。默認(rèn)值為YES攒巍。)
9嗽仪、常用關(guān)鍵字 static、const窑业、 extern钦幔、define
當(dāng)static關(guān)鍵字修飾局部變量時枕屉,只會初始化一次且在程序中只有一份內(nèi)存常柄;
關(guān)鍵字static不可以改變局部變量的作用域,但可延長局部變量的生命周期(直到程序結(jié)束才銷毀)。
當(dāng)static關(guān)鍵字修飾全局變量時西潘,作用域僅限于當(dāng)前文件卷玉,外部類是不可以訪問到該全局變量的(即使在外部使用extern關(guān)鍵字也無法訪問)枷遂。
優(yōu)點:不會影響到其他文件, 同理也不受其他文件影響/不會有命名沖突
const 表示常量, 用來修飾右邊的基本變量或指針變量, 由變量轉(zhuǎn)為常量, 其不可以被修改, 在編譯階段會執(zhí)行檢查, 其存儲區(qū)域位于常量區(qū), 常用于配合 static 或 extern 使用甜刻。
extern:使用其來聲明供外部使用(.h&.m)/使用其來聲明引用外部全局變量等涧郊。
想要訪問全局變量可以使用extern關(guān)鍵字(全局變量定義不能有static修飾)弄抬。
define:字符替換, 在預(yù)編譯期間處理, 使用時系統(tǒng)直接進(jìn)行的文本替換暗膜【嗑常可用于修飾數(shù)據(jù), 函數(shù), 結(jié)構(gòu)體, 方法等, 系統(tǒng)不會對其做類型檢查羊苟。
Static和extern的區(qū)別:
(1)extern修飾的全局變量默認(rèn)是有外部鏈接的寂曹,作用域是整個工程腹备,在一個文件內(nèi)定義的全局變量衬潦,在另一個文件中,通過extern全局變量的聲明植酥,就可以使用全局變量镀岛。
(2)static修飾的全局靜態(tài)變量,作用域是聲明此變量所在的文件友驮。
const 修飾其后面內(nèi)容:
const NSString * name = @"Jersey";
使 *name 指針地址不可變, 實際指向內(nèi)容不受影響, 修改指針地址編譯器報錯漂羊。
NSString const * name = @"Jersey";
同上面寫法一致
NSString * const name = @"Jersey";
使 *name 指針指向內(nèi)容不可變, 指針地址不受影響, 修改內(nèi)容則編譯報錯。
define 與 const 選擇
宏定義是在預(yù)編譯期間處理, 在使用時系統(tǒng)直接進(jìn)行的方法替換, 靜態(tài)變量等則是在編譯期間進(jìn)行的卸留。
宏定義不會系統(tǒng)不會做編譯檢查, 所以類型錯誤也能通過編譯, const 則會做編譯檢查走越。
能顯式的聲明數(shù)據(jù)類型, 并且不會出現(xiàn)自己定義的宏被其他人員更換,導(dǎo)致出現(xiàn)難以排查的 Bug。
不過宏不僅能對數(shù)據(jù)類型進(jìn)行定義, 還能對函數(shù), 結(jié)構(gòu)體, 方法等進(jìn)行定義相對比起常量來說作用會更多一些耻瑟。
編譯時刻:宏是預(yù)編譯, const是編譯階段
編譯檢查:宏不做檢查, 有錯誤不會提示, const會檢查, 有錯誤會提示
宏的優(yōu)點:高效,靈活,可用于替換各種 函數(shù),方法,結(jié)構(gòu)體,數(shù)據(jù)等;
宏的缺點:由于在預(yù)編譯期間完成, 大量使用宏, 容易造成編譯時間久
const優(yōu)點:編譯器通常不為普通 const 常量分配存儲空間, 而是將它們保存在符號表中, 這使得它成為一個編譯期間的常量, 沒有了存儲與讀內(nèi)存的操作, 使得它的效率也很高, 相當(dāng)于宏更加高效, 并且容錯率很低买喧。
const缺點:const 能定義的內(nèi)容非常有限, 只能用于定義常量
宏定義所定義的生命周期與所在的載體的生命周期有關(guān)
const修飾具有就近性, 即 const 后面的參數(shù)是不可變的, const修飾的參數(shù)具有只讀性, 如果試圖修改, 編譯器就會報錯
蘋果官方不推薦我們使用宏, 推薦使用const常量
10、創(chuàng)建字符串常量的方式
在.h文件中extern聲明一些全局的常量匆赃,在.m實現(xiàn)
.h
extern NSString * const url;
.m
NSString * const url = @"www.baidu.com"
11淤毛、category和extension的區(qū)別
區(qū)別 | Category | Extension |
---|---|---|
添加成員變量 | 不可以 | 可以 |
添加屬性 | 不可以(但通過runtime可以) | 可以 |
添加方法 | 可以 | 可以 |
語法格式 | @interface NSObject (category)/@implementation NSObject(category)//注意:括號里有名字 | @interface ClassName ()/@implementation ClassName()//注意:括號里無名字; |
1算柳、Extension通常定義在主類.m文件中低淡,Extension中聲明的方法直接在主類的.m文件中實現(xiàn)。
寫在.h文件里瞬项,屬性蔗蹋、方法公有;
寫在.m文件里囱淋,屬性猪杭、方法私有。
2妥衣、Extension只聲明方法皂吮,不實現(xiàn)方法戒傻,會報警告:Method definition for '方法名' not found
3、為什么要用Category蜂筹?
當(dāng)你已經(jīng)封裝好一個完整的類庫需纳,隨著需求的變化,你發(fā)現(xiàn)需要給類庫中某個類的增加新方法艺挪,為了防止誤調(diào)用引起不必要的麻煩不翩,可以通過增加這個類的分類達(dá)到同樣的效果,方便管理麻裳。
4口蝠、Extension是Category的一種特殊形式。
5津坑、Category里聲明屬性亚皂,不會自動生成帶下劃線的成員變量以及getter/setter方法,需要手動添加get/setter方法国瓮,通過runtime關(guān)聯(lián)對象綁定灭必,訪問不會報錯。
Extension是編譯時自動生成帶下劃線的getter/setter方法乃摹。
6禁漓、Extension中聲明的方法沒被實現(xiàn),編譯器會報警孵睬,但是Category中的方法沒實現(xiàn)編譯器是不會有任何警告的播歼。這是因為Extension是在編譯階段被添加到類中,而Category是在運行時添加到類中掰读。
7秘狞、Extension不能像Category那樣擁有獨立的實現(xiàn)部分(@implementation部分),也就是說蹈集,Extension所聲明的方法必須依托對應(yīng)類的實現(xiàn)部分來實現(xiàn)烁试。
動態(tài)庫和靜態(tài)庫
(iOS里的動態(tài)庫和靜態(tài)庫)
靜態(tài)庫:鏈接時,靜態(tài)庫會被完整地復(fù)制到可執(zhí)行文件中拢肆,被多次使用就有多份冗余拷貝(圖1所示)
系統(tǒng)動態(tài)庫:鏈接時不復(fù)制减响,程序運行時由系統(tǒng)動態(tài)加載到內(nèi)存,供程序調(diào)用郭怪,系統(tǒng)只加載一次支示,多個程序共用,節(jié)省內(nèi)存(圖2所示)
image