一、Runtime
1侠鳄、id、instance
id
使用id修飾的對(duì)象是動(dòng)態(tài)類(lèi)型死宣,只是簡(jiǎn)單的聲明了指向?qū)ο蟮闹羔槨?br> 編譯時(shí)不做類(lèi)型檢查伟恶,可以發(fā)送任何信息給id類(lèi)型的對(duì)象
instanceType
表示某個(gè)方法返回未知類(lèi)型的OC對(duì)象
非關(guān)聯(lián)類(lèi)型的方法返回所在類(lèi)的類(lèi)型
instancetype可以返回和方法所在類(lèi)相同類(lèi)型的對(duì)象,id只能返回未知類(lèi)型的對(duì)象
instancetype只能作為返回值毅该,不能像id一樣作為參數(shù)
2博秫、isa
Apple文檔:
Every object is connected to the run-time system through itsisa instance variable, inherited from the NSObject class.isa identifies the object's class; it points to a structurethat's compiled from the class definition. Through isa, anobject can find whatever information it needs at run timesuch asits place in the inheritance hierarchy, the size and structure ofits instance variables, and the location of the methodimplementations it can perform in response to messages.
isa:是一個(gè)Class 類(lèi)型的指針. 每個(gè)實(shí)例對(duì)象有個(gè)isa的指針,他指向?qū)ο蟮念?lèi),而Class里也有個(gè)isa的指針, 指向meteClass(元類(lèi))眶掌。元類(lèi)保存了類(lèi)方法的列表挡育。當(dāng)類(lèi)方法被調(diào)用時(shí),先會(huì)從本身查找類(lèi)方法的實(shí)現(xiàn)朴爬,如果沒(méi)有即寒,元類(lèi)會(huì)向他父類(lèi)查找該方法。同時(shí)注意的是:元類(lèi)(meteClass)也是類(lèi)召噩,它也是對(duì)象母赵。元類(lèi)也有isa指針,它的isa指針最終指向的是一個(gè)根元類(lèi)(root meteClass).根元類(lèi)的isa指針指向本身,這樣形成了一個(gè)封閉的內(nèi)循環(huán)蚣常。
每一個(gè)對(duì)象本質(zhì)上都是一個(gè)類(lèi)的實(shí)例市咽。其中類(lèi)定義了成員變量和成員方法的列表。對(duì)象通過(guò)對(duì)象的isa指針指向類(lèi)抵蚊。
每一個(gè)類(lèi)本質(zhì)上都是一個(gè)對(duì)象,類(lèi)其實(shí)是元類(lèi)(meteClass)的實(shí)例。元類(lèi)定義了類(lèi)方法的列表贞绳。類(lèi)通過(guò)類(lèi)的isa指針指向元類(lèi)谷醉。
所有的元類(lèi)最終繼承一個(gè)根元類(lèi),根元類(lèi)isa指針指向本身冈闭,形成一個(gè)封閉的內(nèi)循環(huán)俱尼。
3、消息發(fā)送機(jī)制
4萎攒、Method Swizzing(方法交換)
參考文章黑魔法
5遇八、Category、Extension
- Category是運(yùn)行時(shí)決定生效的耍休,Extension是編譯時(shí)就決定生效的
- Category可以為系統(tǒng)類(lèi)添加分類(lèi)刃永,Extension不能
- Category是有聲明和實(shí)現(xiàn),Extension直接寫(xiě)在宿主.m文件羊精,只有聲明
- Category只能擴(kuò)充方法斯够,不能擴(kuò)充成員變量和屬性
- 如果Category聲明了一個(gè)屬性,那么Category只會(huì)生成這個(gè)屬性的set,get方法的聲明,也就不是會(huì)實(shí)現(xiàn)。我們知道在一個(gè)類(lèi)中用@property聲明屬性喧锦,編譯器會(huì)自動(dòng)幫我們生成成員變量和setter/getter读规,但分類(lèi)的指針結(jié)構(gòu)體中,根本沒(méi)有屬性列表燃少。所以在分類(lèi)中用@property聲明屬性束亏,既無(wú)法生成成員變量也無(wú)法生成setter/getter。
因此結(jié)論是:我們可以用@property聲明屬性阵具,編譯和運(yùn)行都會(huì)通過(guò)碍遍,只要不使用程序也不會(huì)崩潰。但如果調(diào)用了_成員變量和setter/getter方法怔昨,報(bào)錯(cuò)就在所難免了雀久。
6、歸檔接檔(NSCoding)
7趁舀、KVC赖捌、KVO
二、Runloop
1矮烹、什么是Runloop
2越庇、Runloop Mode
3、Runloop Source
事件源奉狈,即事件的處理卤唉。CFRunLoopSource 是循環(huán)系統(tǒng)的事件輸入源,輸入源通常會(huì)產(chǎn)生異步事件仁期,然后隨著 RunLoop 生命周期的進(jìn)行不斷執(zhí)行回調(diào)桑驱。Source 有兩個(gè)版本:Source0 和 Source1竭恬。Source0 只包含了一個(gè)回調(diào)(函數(shù)指針),它并不能主動(dòng)觸發(fā)事件熬的。使用時(shí)痊硕,你需要先調(diào)用 CFRunLoopSourceSignal(source),將這個(gè) Source 標(biāo)記為待處理押框,然后手動(dòng)調(diào)用 CFRunLoopWakeUp(runloop) 來(lái)喚醒 RunLoop岔绸,讓其處理這個(gè)事件。Source1 包含了一個(gè) mach_port 和一個(gè)回調(diào)(函數(shù)指針)橡伞,被用于通過(guò)內(nèi)核和其他線程相互發(fā)送消息盒揉。這種 Source 能主動(dòng)喚醒 RunLoop 的線程。
4兑徘、Runloop Observer
觀察者刚盈,即 RunLoop 生命周期的回調(diào)。每個(gè) Observer 都包含了一個(gè)回調(diào)(函數(shù)指針)道媚,當(dāng) RunLoop 的狀態(tài)發(fā)生變化時(shí)扁掸,觀察者就能通過(guò)回調(diào)接受到這個(gè)變化。
5最域、Runloop運(yùn)行邏輯
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即將進(jìn)入 RunLoop
kCFRunLoopBeforeTimers = (1UL << 1), // 即將處理 Timer
kCFRunLoopBeforeSources = (1UL << 2), // 即將處理 Source
kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進(jìn)入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 剛從休眠被喚醒
kCFRunLoopExit = (1UL << 7), // 即將退出 RunLoop
kCFRunLoopAllActivities = 0x0FFFFFFFU // 任意上述活動(dòng)
};
6谴分、如何實(shí)現(xiàn)常駐線程
- (void)run{
//只要往RunLoop中添加了 timer、source或者observer就會(huì)繼續(xù)執(zhí)行镀脂,一個(gè)Run Loop通常必須包含一個(gè)輸入源或者定時(shí)器來(lái)監(jiān)聽(tīng)事件牺蹄,如果一個(gè)都沒(méi)有,Run Loop啟動(dòng)后立即退出薄翅。
@autoreleasepool {
//1沙兰、添加一個(gè)input source
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
//2、添加一個(gè)定時(shí)器
// NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
// [[NSRunLoop currentRunLoop] run];
}
}
三翘魄、Block
1鼎天、Block原理
2、堆Block暑竟、棧Block斋射、全局Block
3、Block變量捕獲
4但荤、_ _block _ _weak
- _ _block不管是ARC還是MRC下都能使用罗岖,可以修飾對(duì)象,還可以修飾基本數(shù)據(jù)類(lèi)型腹躁。
- _ _weak只能在ARC下使用桑包,只能修飾對(duì)象,不能修飾基本數(shù)據(jù)類(lèi)型纺非。
- _ _block對(duì)象可以在block中被重新賦值哑了, _ _weak不可以赘方。
- _ _ block對(duì)象在ARC下可能會(huì)導(dǎo)致循環(huán)引用,非ARC下會(huì)避免循環(huán)引用垒手; _ _weak只能在ARC下使用蒜焊,可以避免循環(huán)引用倒信。
5科贬、Weakself
四、內(nèi)存管理
1鳖悠、引用計(jì)數(shù)
2榜掌、MRC和ARC
3、weak乘综、assign憎账、strong與copy
weak
只可以修飾對(duì)象。如果修飾基本數(shù)據(jù)類(lèi)型卡辰,編譯器會(huì)報(bào)錯(cuò)胞皱。weak 不會(huì)產(chǎn)生野指針問(wèn)題。因?yàn)閣eak修飾的對(duì)象釋放后(引用計(jì)數(shù)器值為0)九妈,指針會(huì)自動(dòng)被置nil反砌,之后再向該對(duì)象發(fā)消息也不會(huì)崩潰。 因此萌朱,weak適用于delegate和block等引用類(lèi)型宴树,不會(huì)導(dǎo)致野指針問(wèn)題,也不會(huì)循環(huán)引用晶疼。
assign
可修飾對(duì)象酒贬,和基本數(shù)據(jù)類(lèi)型。當(dāng)需要修飾對(duì)象類(lèi)型時(shí)翠霍,MRC下使用unsafe_unretained锭吨。assign 如果修飾對(duì)象,會(huì)產(chǎn)生野指針問(wèn)題寒匙;如果修飾基本數(shù)據(jù)類(lèi)型則是安全的零如。修飾的對(duì)象釋放后,指針不會(huì)自動(dòng)被置空蒋情,此時(shí)向?qū)ο蟀l(fā)消息會(huì)崩潰埠况。因此assign 適用于基本數(shù)據(jù)類(lèi)型如int,float,struct等值類(lèi)型,不適用于引用類(lèi)型棵癣。因?yàn)橹殿?lèi)型會(huì)被放入棧中辕翰,遵循先進(jìn)后出原則,由系統(tǒng)負(fù)責(zé)管理?xiàng)?nèi)存狈谊。而引用類(lèi)型會(huì)被放入堆中喜命,需要我們自己手動(dòng)管理內(nèi)存或通過(guò)ARC管理沟沙。
strong與copy
兩者修飾的對(duì)象在引用時(shí)引用計(jì)數(shù)都會(huì)加1,常見(jiàn)題NSString在聲明時(shí)用strong還是copy修飾(參考文章http://www.reibang.com/p/b3873ac9259b)
4壁榕、深copy與淺copy
引申一個(gè)小知識(shí)矛紫,地址有兩種情況:
- 指針的內(nèi)存地址
- 指針指向的對(duì)象的內(nèi)存地址
所以打印內(nèi)存地址的正確姿勢(shì)如下:
NSString *string = @"Jianshu";
NSLog(@"指針?biāo)赶驅(qū)ο蟮膬?nèi)存地址:%p",string);
NSLog(@"指針自己的內(nèi)存地址:%p",&string);
深拷貝就是拷貝出和原來(lái)僅僅是值一樣,但是內(nèi)存地址完全不一樣的新的對(duì)象牌里,創(chuàng)建后和原對(duì)象沒(méi)有任何關(guān)系颊咬。深拷貝是真正意義上的拷貝,是創(chuàng)建一個(gè)新對(duì)象牡辽。copy屬性表示兩個(gè)對(duì)象內(nèi)容相同喳篇,新的對(duì)象retain為1,與原對(duì)象的引用計(jì)數(shù)無(wú)關(guān)态辛,原對(duì)象沒(méi)有改變麸澜。copy減少對(duì)象對(duì)上下文的依賴。
淺拷貝就是拷貝指向原來(lái)對(duì)象的指針奏黑,使原對(duì)象的引用計(jì)數(shù)+1炊邦,可以理解為創(chuàng)建了一個(gè)指向原對(duì)象的新指針而已,并沒(méi)有創(chuàng)建一個(gè)全新的對(duì)象熟史。淺拷貝類(lèi)似retain馁害,引用計(jì)數(shù)對(duì)象+1,創(chuàng)建一個(gè)指針以故。
5蜗细、atomic(原子性)和noatomic(非原子性)
Apple文檔
原子操作是不可分割的操作,在原子操作執(zhí)行完畢之前怒详,其不會(huì)被任何其它任務(wù)或事件中斷炉媒。
atomic與nonatomicd的主要區(qū)別就是系統(tǒng)自動(dòng)生成的getter/setter方法不一樣
- atomic系統(tǒng)自動(dòng)生成的getter/setter方法會(huì)進(jìn)行加鎖操作,不同線程上的操作都將依次順序執(zhí)行
- nonatomic系統(tǒng)自動(dòng)生成的getter/setter方法不會(huì)進(jìn)行加鎖操作昆烁,不同線程上的操作可以同時(shí)執(zhí)行吊骤,可能導(dǎo)致無(wú)法預(yù)料的結(jié)果。
假設(shè)有一個(gè) atomic 的屬性 "name"静尼,如果線程 A 調(diào)[self setName:@"A"]
白粉,線程 B 調(diào)[self setName:@"B"]
,線程 C 調(diào)[self name]
鼠渺,那么所有這些不同線程上的操作都將依次順序執(zhí)行鸭巴,也就是說(shuō),如果一個(gè)線程正在執(zhí)行 getter/setter拦盹,其他線程就得等待鹃祖。因此,屬性 name 是讀/寫(xiě)安全的普舆。
但是恬口,如果有另一個(gè)線程 D 同時(shí)在調(diào)[name release]校读,那可能就會(huì)crash,因?yàn)?release 不受 getter/setter 操作的限制祖能。也就是說(shuō)歉秫,這個(gè)屬性只能說(shuō)是讀/寫(xiě)安全的,但并不是線程安全的养铸,因?yàn)閯e的線程還能進(jìn)行讀寫(xiě)之外的其他操作雁芙。線程安全需要開(kāi)發(fā)者自己來(lái)保證。
如果 name 屬性是 nonatomic 的揭厚,那么上面例子里的所有線程 A却特、B、C筛圆、D 都可以同時(shí)執(zhí)行,可能導(dǎo)致無(wú)法預(yù)料的結(jié)果椿浓。如果是 atomic 的太援,那么 A、B扳碍、C 會(huì)串行提岔,而 D 還是并行的。
6笋敞、內(nèi)存泄漏
7碱蒙、循環(huán)引用
五、多線程
1夯巷、GCD
2赛惩、NSOperation
3、NSThread
六趁餐、iOS網(wǎng)絡(luò)
1喷兼、TCP三次握手
三次握手主要是
為了防止已失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端,因而產(chǎn)生錯(cuò)誤,假設(shè)這是一個(gè)早已失效的報(bào)文段。但 serverl收到此失效的連接請(qǐng)求報(bào)文段后,就誤認(rèn)為是 client再次發(fā)出的一個(gè)新的連接請(qǐng)求后雷。于是就向 client發(fā)出確認(rèn)報(bào)文段,同意建立連接季惯。假設(shè)不采用“三次握手”,那么只要 server發(fā)出確認(rèn),新的連接就建立了。由于現(xiàn)在 client并沒(méi)有發(fā)出建立連接的請(qǐng)求,因此不會(huì)理睬 server的確認(rèn),也不會(huì)向 server發(fā)送數(shù)據(jù),但 Server卻以為新的運(yùn)輸連接已經(jīng)建立,并直等待cent發(fā)來(lái)數(shù)據(jù),這樣, server的很多資源就白白浪費(fèi)掉了臀突。
2勉抓、TCP四次揮手
四次揮手主要是因?yàn)門(mén)CP是全雙工通信的,在接收到客戶端的關(guān)閉請(qǐng)求時(shí),還可能在向客戶端發(fā)送著數(shù)據(jù),因此不能再回應(yīng)關(guān)閉鏈接的請(qǐng)求時(shí),同時(shí)發(fā)送關(guān)閉鏈接的請(qǐng)求。