1. load方法和initialize方法
相同點(diǎn)
- 在不考慮開發(fā)者主動使用的情況下,系統(tǒng)最多會調(diào)用一次
- 如果父類和子類都被調(diào)用,父類的調(diào)用一定在子類之前
- 都是為了應(yīng)用運(yùn)行提前創(chuàng)建合適的運(yùn)行環(huán)境
- 在使用時都不要過重地依賴于這兩個方法,除非真正必要
load
- 調(diào)用時間早于initialize,main函數(shù)之前,不會觸發(fā)initialize的調(diào)用
- 對于有依賴關(guān)系的類,要確保被依賴類的load優(yōu)先調(diào)用
- 沒有l(wèi)oad方法的實(shí)現(xiàn),不會調(diào)用父類的的load方法
- Category的load也會收到調(diào)用,順序在主類之后
- Method Swizzleu一般會放在load中執(zhí)行
initialize
- 懶加載,第一次主動使用類時調(diào)用
- 子類不實(shí)現(xiàn)initialize方法,會把父類的實(shí)現(xiàn)繼承過來調(diào)用一遍
- 都是線程安全的,不要再使用鎖
2.block
數(shù)據(jù)結(jié)構(gòu)
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
類型
- _NSConcreteGlobalBlock 全局的靜態(tài) block,不會訪問任何外部變量。
- _NSConcreteStackBlock 保存在棧中的 block,當(dāng)函數(shù)返回時會被銷毀。
- _NSConcreteMallocBlock 保存在堆中的 block,當(dāng)引用計數(shù)為 0 時會被銷毀。
變量的復(fù)制
- block外變量的引用,是復(fù)制到數(shù)據(jù)結(jié)構(gòu)中訪問
- __block修飾的外部變量,是復(fù)制其引用地址來實(shí)現(xiàn)訪問
ARC和MRC下的block
配置在棧上的Block也就是NSStackBlock類型的Block,如果其所屬的變量作用域結(jié)束該Block就會廢棄。這個時候如果繼續(xù)使用該Block,就應(yīng)該使用copy方法,將NSStackBlock拷貝為NSMallocBlock。當(dāng)NSMallocBlock的引用計數(shù)變?yōu)?,該NSMallocBlock就會被釋放。
如果是非ARC環(huán)境,需要顯式的執(zhí)行copy或者antorelease方法。
而當(dāng)ARC有效的時候,實(shí)際上大部分情況下編譯器已經(jīng)為我們做好了,自動的將Block從棧上復(fù)制到堆上。包括以下幾個情況:
- Block作為返回值時,類似在非ARC的時候,對返回值Block執(zhí)行[[returnedBlock copy] autorelease];
- 方法的參數(shù)中傳遞Block時
- Cocoa框架中方法名中還有useringBlock等時
- GCD相關(guān)的一系列API傳遞Block時
對于非ARC下,為了防止循環(huán)引用,我們使用__block
來修飾在Block中使用的對象。
對于ARC下,為了防止循環(huán)引用,我們使用__weak
來修飾在Block中使用的對象。
循環(huán)引用和野指針
block和對象互相強(qiáng)引用,引起引用循環(huán),使用弱引用打破循環(huán)。block使用的對象被提前釋放,產(chǎn)生了野指針,會引起crash,要注意對象的生命周期。
參考鏈接
談Objective-C block的實(shí)現(xiàn)
正確使用Block避免Cycle Retain和Crash
3.ARC
ARC是編譯特性,不是垃圾回收,本質(zhì)還是計數(shù)式內(nèi)存管理,在ARC特性下有4種與內(nèi)存管理息息相關(guān)的變量所有權(quán)修飾符值得我們關(guān)注:
變量所有權(quán)修飾符 | 屬性修飾符 |
---|---|
__strong | copy retain strong |
__weak | weak |
__autoreleasing | N/A |
__unsafe_unretaied | assign unsafe_unretained |
__autoreleasing
在 ARC 模式下,我們不能顯示的使用 autorelease 方法了
__unsafe_unretained
ARC 是在 iOS5 引入的,而 __unsafe_unretained 這個修飾符主要是為了在 ARC 剛發(fā)布時兼容 iOS4 以及版本更低的系統(tǒng),因?yàn)檫@些版本沒有弱引用機(jī)制
關(guān)于 Toll-Free Bridging
在 MRC 時代,由于 Objective-C 類型的對象和 Core Foundation 類型的對象都是相同的 release 和 retain 操作規(guī)則,所以 Toll-Free Bridging 的使用比較簡單,但是自從切換到 ARC 后,Objective-C 類型的對象內(nèi)存管理規(guī)則改變了,而 Core Foundation 依然是之前的機(jī)制,換句話說,Core Foundation 不支持 ARC。是蘋果在引入 ARC 之后對 Toll-Free Bridging 的操作也加入了對應(yīng)的方法與修飾符,用來指明用哪種規(guī)則管理內(nèi)存,或者說是內(nèi)存管理權(quán)的歸屬。這些方法和修飾符分別是:
- __bridge(修飾符)-- 只是聲明類型轉(zhuǎn)變,但是不做內(nèi)存管理規(guī)則的轉(zhuǎn)變。
- __bridge_retained(修飾符) or CFBridgingRetain(函數(shù))-- 內(nèi)存管理的責(zé)任由原來的 Objective-C 交給Core Foundation 來處理,也就是,將 ARC 轉(zhuǎn)變?yōu)?MRC
- __bridge_transfer(修飾符) or CFBridgingRelease(函數(shù))-- 內(nèi)存管理的責(zé)任由 Core Foundation 轉(zhuǎn)交給 Objective-C,即將管理方式由 MRC 轉(zhuǎn)變?yōu)?ARC。
參考鏈接:
iOS ARC 內(nèi)存管理要點(diǎn)
4.RunLoop
概念
線程能隨時處理事件但并不退出的模型通常被稱為Event Loop,RunLoop實(shí)際上是一個對象,這個對象管理了其需要處理的事件和消息,并提供了一個入口函數(shù)來執(zhí)行上面 Event Loop 的邏輯。線程執(zhí)行了這個函數(shù)后,就會一直處于這個函數(shù)內(nèi)部 "接受消息->等待->處理" 的循環(huán)中,直到這個循環(huán)結(jié)束(比如傳入 quit 的消息),函數(shù)返回。
和線程的關(guān)系
RunLoop和線程一一對應(yīng),RunLoop的創(chuàng)建發(fā)生在線程第一次獲取時,只能在線程內(nèi)獲取自身的RunLoop(主線程除外)。蘋果不允許直接創(chuàng)建 RunLoop,它只提供了兩個自動獲取的函數(shù):CFRunLoopGetMain() 和 CFRunLoopGetCurrent()。
相關(guān)類
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef
一個 RunLoop 包含若干個 Mode,每個 Mode 又包含若干個 Source/Timer/Observer。每次調(diào)用 RunLoop 的主函數(shù)時,只能指定其中一個 Mode,這個Mode被稱作 CurrentMode。如果需要切換 Mode,只能退出 Loop,再重新指定一個 Mode 進(jìn)入。這樣做主要是為了分隔開不同組的 Source/Timer/Observer,讓其互不影響。
Mode
系統(tǒng)默認(rèn)注冊了5個Mode:
- kCFRunLoopDefaultMode: App的默認(rèn) Mode,通常主線程是在這個 Mode 下運(yùn)行的。
- UITrackingRunLoopMode: 界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響。
- UIInitializationRunLoopMode: 在剛啟動 App 時第進(jìn)入的第一個 Mode,啟動完成后就不再使用。
- GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到。
- kCFRunLoopCommonModes: 這是一個占位的 Mode,沒有實(shí)際作用。
參考鏈接
深入理解RunLoop
5.UIView
UIView繼承于UIResponder類,因此它主要表達(dá)了兩個意思
1.可視(CALayer)
2.可互交(UIResponder)
每個UIView都有一個隱式層(implicit Layer),View本身就是這個隱式層的Delegate.
Layer又有兩部分組成。present layer和Model layer.
present layer表示了中間的過程狀態(tài),而Model layer則表示了起始和結(jié)束狀態(tài)
loadView
loadView在View為nil時調(diào)用,早于ViewDidLoad,通常用于代碼實(shí)現(xiàn)控件,收到內(nèi)存警告時會再次調(diào)用。loadView默認(rèn)做的事情是:加載nib。如果你想自己創(chuàng)建View對象,那么可以重載這個方法。
UIWindow
- UIWindow是一種特殊的UIView,通常在一個app中至少會有一個UIWindow。
- iOS程序啟動完畢后,創(chuàng)建的第一個視圖控件就是UIWindow,接著創(chuàng)建控制器的View,最后將控制器的View添加到UIWindow上,于是控制器的View就顯示在屏幕上了。
- 一個iOS程序之所以能顯示在屏幕上,完全是因?yàn)樗蠻IWindow,也就是說,沒有UIWindow就看不到任何UI界面。
- 狀態(tài)欄和鍵盤都是特殊的UIWindow。
UIWindow有三個層級,分別是Normal,StatusBar,Alert。
keyWindow是指定的用來接收鍵盤以及非觸摸類的消息,而且程序中每一個時刻只能有一個window是keyWindow。
6.沙盒和bundle
沙盒目錄結(jié)構(gòu)
- Application:存放程序源文件,上架前經(jīng)過數(shù)字簽名,上架后不可修改
- Documents:常用目錄,iCloud備份目錄,存放數(shù)據(jù),這里不能存緩存文件,否則上架不被通過
Library - Caches:存放體積大又不需要備份的數(shù)據(jù),SDWebImage緩存路徑就是這個
Preference:設(shè)置目錄,iCloud會備份設(shè)置信息 - tmp:存放臨時文件,不會被備份,而且這個文件下的數(shù)據(jù)有可能隨時被清除的可能
App Bundle 里面有什么
- Info.plist:此文件包含了應(yīng)用程序的配置信息.系統(tǒng)依賴此文件以獲取應(yīng)用程序的相關(guān)信息
- 可執(zhí)行文件:此文件包含應(yīng)用程序的入口和通過靜態(tài)連接到應(yīng)用程序target的代碼
- 資源文件:圖片,聲音文件一類的
- 其他:可以嵌入定制的數(shù)據(jù)資源
7.屬性
修飾符
- atomic,nonatomic -- 原子性
- readonly,readwrite -- 訪問權(quán)限
- assign,strong,weak,copy -- ARC內(nèi)存管理
- assign,retain,copy -- MRC內(nèi)存管理
- setter=,getter= -- 指定方法名稱
assign和weak的區(qū)別
assign修飾的數(shù)據(jù)內(nèi)存由系統(tǒng)清理,對于基礎(chǔ)數(shù)據(jù)類型,生存周期為整個棧周期,可以由棧處理。修飾對象時,如果這個對象被其他過程釋放(即指向的堆內(nèi)存被釋放),對象的指針地址依然存在,形成野指針。weak不能修飾基礎(chǔ)類型數(shù)據(jù),修飾對象時,如果對象被釋放,指針會自動置為nil。
實(shí)現(xiàn)原理
在普通的OC對象中,@property就是編譯器自動幫生成一個私有的成員變量和setter與getter方法的聲明和實(shí)現(xiàn)
protocol 和 category
- 在protocol中使用property只會生成setter和getter方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對象的實(shí)現(xiàn)該屬性
- category 使用 @property 也是只會生成setter和getter方法的聲明,如果我們真的需要給category增加屬性的實(shí)現(xiàn),需要借助于運(yùn)行時的兩個函數(shù)
objc_setAssociatedObject
objc_getAssociatedObject
8.cocoapods原理
- 將所有的依賴庫都放到另一個名為 Pods 項(xiàng)目中
- Pods 項(xiàng)目最終會編譯成一個名為 libPods.a 的文件,主項(xiàng)目只需要依賴這個 .a 文件即可。這樣,依賴庫源碼管理工作都從主項(xiàng)目移到了 Pods 項(xiàng)目中。
- 對于資源文件,CocoaPods 提供了一個名為 Pods-resources.sh 的 bash 腳本,該腳本在每次項(xiàng)目編譯的時候都會執(zhí)行,將第三方庫的各種資源文件復(fù)制到目標(biāo)目錄中。
- CocoaPods 通過一個名為 Pods.xcconfig 的文件來在編譯時設(shè)置所有的依賴和參數(shù)。
9. Instruments常用功能
- Time Profiler:性能分析
- Zombies:檢查是否訪問了僵尸對象
- Allocations:用來檢查內(nèi)存,寫算法的那批人也用這個來檢查
- Leaks:檢查內(nèi)存,看是否有內(nèi)存泄露
10.nil / Nil / NULL / NSNull
標(biāo)志 | 值 | 含義 |
---|---|---|
NULL | (void *)0 | C指針的字面零值 |
nil | (id)0 | Objective-C對象的字面零值 |
Nil | (Class)0 | Objective-C類的字面零值 |
NSNull | [NSNull null] | 用來表示零值的單獨(dú)的對象 |
to be continued