iOS基礎(chǔ)面試題
1先蒋、#import 跟#include 又什么區(qū)別万栅,@class呢? #import<> 跟 #import"" 有什么區(qū)別悠鞍?
- #import是OC引入頭類文件的關(guān)鍵字染簇,#include是C/C++引入頭文件的關(guān)鍵字参滴;#import引入的頭文件,無論你引入幾次锻弓,都會只做一次引入操作卵洗,防止重復(fù)倒入,相當(dāng)于#include+#pragma once;
- @class 是聲明類的弥咪,多用于頭文件相互引用过蹂;
- #import<>用于導(dǎo)入系統(tǒng)頭文件和三方庫,#import"" 用于導(dǎo)入用戶頭文件聚至。
2酷勺、屬性atomic/nonatomic,assign/week/retain/strong/copy扳躬,readwrite/readonly ,@synthesize/@dynamic各是什么作用脆诉,在那種情況下用?
- atomic:原子性訪問屬性贷币,會對setter和getter方法加鎖击胜,保證屬性讀寫是安全的;但是在多線程中對集合類元素的添加刪除操作沒有加鎖役纹,無法保證線程安全偶摔;由于對讀寫方法加鎖操作,導(dǎo)致性能降低促脉。
- noatomic:非原子性訪問屬性辰斋,無法保證線程安全策州,但是性能比atomic有提升。由于atomic并不能完全保證線程安全宫仗,所以一般使用noatomic够挂。
- assign:assign修飾基礎(chǔ)數(shù)據(jù)類型或?qū)ο箢愋停粫挂糜?jì)數(shù)+1藕夫;修飾對象類型時(shí)孽糖,和week類似,但是在指向?qū)ο蟊会尫艜r(shí)毅贮,不會把指針指向nil办悟,容易造成野指針crash,所以一般用于修飾基礎(chǔ)數(shù)據(jù)類型嫩码。
- week:week只能修飾對象類型屬性,不會使引用計(jì)數(shù)+1罪既,當(dāng)對象釋放時(shí)铸题,指針會指向nil;runtime會維護(hù)一個week表琢感,是一個哈希表丢间,key為week指針指向的對象的地址,value為所有指向這個對象的week指針的地址數(shù)組驹针;當(dāng)該對象引用計(jì)數(shù)為0時(shí)烘挫,runtime會根據(jù)對象地址查找對應(yīng)的弱引用數(shù)組,然后遍歷數(shù)組柬甥,把所有的week指針指向nil饮六,避免野指針的出現(xiàn)。
- retain/strong:修飾對象屬性苛蒲,使引用計(jì)數(shù)+1卤橄,ARC下一般使用strong;
- copy:一般用于NSString和block臂外,屬性賦值時(shí)窟扑,會copy一份新變量給屬性變量;
- readwrite:可讀寫屬性漏健,默認(rèn)屬性修飾關(guān)鍵字嚎货;
- readonly:只讀屬性,不允許外部修改屬性變量蔫浆;可通過KVC修改屬性變量值殖属,但不建議。
- @synthesize:告訴編譯器瓦盛,需要為該屬性生成setter和getter方法忱辅,默認(rèn)修飾七蜘;一般用于類實(shí)現(xiàn)protocol屬性時(shí);
- @dynamic:告訴編譯器墙懂,不生成setter和getter方法橡卤,將有程序員自己實(shí)現(xiàn)。
3损搬、淺copy和深copy
- 淺copy是指針copy碧库,copy一份指針,指向?qū)ο髢?nèi)存地址巧勤,使對象引用計(jì)數(shù)+1嵌灰;
- 深copy是對象內(nèi)存copy,會copy一份對象到新的內(nèi)存地址颅悉,不會使對象引用計(jì)數(shù)+1沽瞭;
- 不可變集合類的copy是淺copy,mutableCopy是深copy剩瓶;
- 可變集合類的copy和mutableCopy都是深copy驹溃;
4、引用計(jì)數(shù)和AutoreleasePool
- 當(dāng)我們創(chuàng)建一個對象時(shí)延曙,它的引用計(jì)數(shù)會+1豌鹤,系統(tǒng)會為對象分配內(nèi)存;每當(dāng)對象有一個新的引用枝缔,引用計(jì)數(shù)+1布疙,每當(dāng)對象取消一個引用,引用計(jì)數(shù)-1愿卸;當(dāng)對象引用計(jì)數(shù)為0灵临,系統(tǒng)會釋放該對象內(nèi)存。
- MRC下趴荸,使用retain方法使對象引用計(jì)數(shù)+1俱诸,避免被釋放;使用release使引用計(jì)數(shù)-1赊舶,釋放對對象的引用睁搭;
- ARC下,編譯器會自動插入retain和release操作笼平,不需要我們手動管理內(nèi)存园骆;
- AutoreleasePool是由AutoreleasePoolPage構(gòu)成的雙向鏈表,當(dāng)runloop啟動時(shí)寓调,會創(chuàng)建AutoreleasePool锌唾,并將所有標(biāo)記延遲釋放的對象加入自動釋放池,當(dāng)runloop退出時(shí),自動釋放池里的對象會被釋放晌涕。(手動創(chuàng)建的自動釋放池里的對象會在AutoreleasePool{}大括號結(jié)尾處釋放)滋捶;當(dāng)調(diào)用push方式時(shí),會把一個POOL_BOUNDARY對象加入page并返回其地址余黎,當(dāng)調(diào)用pop方法時(shí)傳入POOL_BOUNDARY地址重窟,并從最后入棧的對象開始一直到POOL_BOUNDARY的位置之間的對象,全部調(diào)用release惧财,id *next地址指向下一個能存放auto release對象的地方巡扇;
- 由new、alloc垮衷、copy厅翔、mutableCopy關(guān)鍵字生成的對象會被生成者持有,ARC下系統(tǒng)會在合適的時(shí)機(jī)release搀突,不會進(jìn)入AutoreleasePool刀闷,被一般類方法比如+(instancetype)createModelWith:創(chuàng)建的對象,會被標(biāo)記為autorelease仰迁,會被自動加入最近創(chuàng)建的釋放池中甸昏;
- 子線程沒有啟動runloop時(shí),沒有創(chuàng)建自動釋放池轩勘,當(dāng)有對象被標(biāo)記為auto releasing時(shí)筒扒,才會創(chuàng)建怯邪,并把對象加入自動釋放池绊寻,當(dāng)子線程退出時(shí),自動釋放池里的對象會被release悬秉。
常見的autoreleasepool使用
for(inti=0; i<1000000; i++) {
NSString * str = [NSString stringWithFormat:@"abcdefghijklmn1234566!@#$"];
}
for(inti=0; i<1000000; i++) {
@autoreleasepool {
NSString * str = [NSString stringWithFormat:@"abcdefghijklmn1234566!@#$"];
}
}
- 野指針和僵尸對象:指針指向的對象已被釋放澄步,內(nèi)存被回收了,那么這個對象就叫僵尸對象和泌,指向這個對象的指針村缸,就是野指針。向指向nil的指針發(fā)送消息武氓,不會crash梯皿,向指向僵尸對象的野指針發(fā)送消息會crash;
- Tagged Pointer:從64bit開始县恕,iOS引入tagged pointer技術(shù)东羹,用于解決NSNumber、NSDate忠烛、NSString數(shù)據(jù)比較小時(shí)的存儲問題属提;tagged pointer之前,這些對象需要動態(tài)分配內(nèi)存,對象的指針存儲的是堆上對象的地址冤议,tagged pointer之后斟薇,NSNumber對象指針存儲的是tag+data,也就是指針直接存儲了數(shù)據(jù)恕酸,當(dāng)指針不夠存儲數(shù)據(jù)時(shí)堪滨,才會走動態(tài)內(nèi)存分配,把對象存在堆上尸疆。
5椿猎、KVC、KVO
- KVC:健值編碼模式寿弱,是通過對象的成員變量名犯眠,對對象的成員變量進(jìn)行讀寫的方法。通過-setValue:forKey:寫值症革,通過-valueForKey:讀值筐咧;KVC在寫值和讀值時(shí)會優(yōu)先通過setter和getter方法,然后再去通過key值找對應(yīng)的變量噪矛;如果沒有找到量蕊,就會走-setValue:forUnderfindKey:和-valueForUnderfindKey:方法,如果這兩個方法沒有實(shí)現(xiàn)艇挨,則程序?qū)rash残炮。
- -setValue:forKey: 依次通過查找方法-setKey: 、-_setKey: 缩滨、-setIsKey: 如果找到就調(diào)用势就,如果沒找到,就走+(BOOL)accessInstanceVariablesDirectly方法脉漏,返回YES(默認(rèn)YES)苞冯,接著找_key、_isKey侧巨、key舅锄、isKey成員變量,有的話直接賦值沒有的話走司忱,-setValue:forUnderfindKey:皇忿;返回NO走-setValue:forUnderfindKey:
- -valueForKey: 依次通過-getKey、-key坦仍、-isKey鳍烁、-_key方法,如果沒找到桨踪,就走+(BOOL)accessInstanceVariablesDirectly方法老翘,返回YES(默認(rèn)YES),接著找_key、_isKey铺峭、key墓怀、isKey成員變量,有的話直接取值返回卫键;
- -setValue:forKeyPath:和-valueForKeyPath用于對多級的對象屬性賦值傀履,或者對集合類元素的屬性賦值
- 對于可變字典:NSMutableDictionary來說,使用-setValue:forKey:莉炉,內(nèi)部會走-setObject:forKey:钓账,其中使用-setValue:forKey:時(shí),value可以為nil絮宁,為nil時(shí)梆暮,會走-removeObjectForKey:刪除健值對,key只能為字符串類型绍昂;使用-setObject:forKey:時(shí)啦粹,value不能為nil,key可以為任意對象(遵守NSCopying協(xié)議的對象)
- KVO:健值監(jiān)聽窘游,是觀察者模式的一種實(shí)現(xiàn)唠椭。KVO是基于runtime實(shí)現(xiàn)的,A對象對B對象的屬性的改變做出監(jiān)聽的一種開發(fā)模式忍饰;runtime會創(chuàng)建B類的一個名字為NSKVONotifying_B的子類贪嫂,并把B對象的is a指針指向這個子類,子類重寫對應(yīng)的屬性setter方法艾蓝,增加了-willChangeValueForKey:和-didChangeValueForKey:方法的調(diào)用力崇,當(dāng)對應(yīng)屬性值改變時(shí)通知觀察者A對象,該屬性已經(jīng)改變饶深。
6餐曹、代理逛拱、通知敌厘、KVO
三種模式都是對象之間事件傳遞的一種方式;
- 通知:一對多朽合,多對多俱两。優(yōu)點(diǎn)是一對多,多對多曹步;可跨越多個層級之間傳遞消息宪彩,代碼解耦;缺點(diǎn)是字符串硬編碼讲婚,編譯期不容易排查錯誤尿孔;代碼比較分散不容易維護(hù)。
- 代理:一對一;優(yōu)點(diǎn)是方案簡便活合,代碼比較緊湊雏婶,方便閱讀調(diào)試和維護(hù);缺點(diǎn)是代碼需要寫的比較多白指;典型的是TableView的delegate和dataSource留晚;
- KVO:一對一;優(yōu)點(diǎn)實(shí)時(shí)監(jiān)聽對象變化告嘲,實(shí)現(xiàn)同步错维;高聚合,監(jiān)聽變化和處理變化在一起容易維護(hù)橄唬;缺點(diǎn)是赋焕。。仰楚。感覺沒啥宏邮,主要看實(shí)際開發(fā)中適合選用那種方案。
7缸血、擴(kuò)展(Extension)蜜氨、分類(Category)、繼承捎泻、協(xié)議(Protocol)飒炎;面向?qū)ο笠约癘C動態(tài)語言特性
- 擴(kuò)展-Extension:擴(kuò)展是一種特殊的分類,可以在類聲明之外笆豁,為類聲明額外的屬性郎汪、實(shí)力變量、方法闯狱、協(xié)議等煞赢,但是不需要實(shí)現(xiàn)具體的@implementation;優(yōu)點(diǎn):一般用于封裝組件時(shí)隱藏不希望暴露的屬性和方法哄孤;缺點(diǎn)是所聲明屬性方法等只能在類內(nèi)部使用照筑,不能被繼承;
- 分類-Category:在不改變現(xiàn)有類的情況下瘦陈,為類添加新的方法凝危;優(yōu)點(diǎn):不改變原始類;可以運(yùn)行時(shí)動態(tài)調(diào)用新方法晨逝;可以拆分工作量大的類蛾默,使代碼結(jié)構(gòu)更清晰,更容易維護(hù)捉貌;可以為系統(tǒng)類NSArray等常用類添加便捷方法支鸡,提高代碼復(fù)用冬念。缺點(diǎn):不能調(diào)用原有類的私有屬性和方法;濫用分類覆蓋系統(tǒng)類方法牧挣,會造成不可控的風(fēng)險(xiǎn)刘急;多處對同一個類寫分類有可能會有命名沖突抑堡,導(dǎo)致方法覆蓋令杈,出現(xiàn)不可控風(fēng)險(xiǎn)。
- 繼承:子類繼承父類的屬性和方法乘碑,提高代碼復(fù)用检碗;繼承是面向?qū)ο蟮囊粋€基礎(chǔ)据块;
- 協(xié)議-Protocol:協(xié)議是定義一套方法或?qū)傩裕惶峁?shí)現(xiàn)折剃,由具體的類實(shí)現(xiàn)協(xié)議的能力另假;優(yōu)點(diǎn)是一套協(xié)議由多個類實(shí)現(xiàn)相同接口不同的能力;
- 封裝(只暴露使用接口怕犁,隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié))边篮、繼承(子類繼承父類的屬性方法)、多態(tài)(運(yùn)行時(shí)才確定接口的具體實(shí)現(xiàn))奏甫,是OC為面向?qū)ο缶幊痰幕A(chǔ)戈轿;
- 動態(tài)是指:類型檢查和消息發(fā)送是在運(yùn)行時(shí)才確定的;動態(tài)綁定阵子、動態(tài)類型思杯、動態(tài)加載是OC的動態(tài)特性。
8挠进、const色乾、宏定義、static领突、extern
- const:常量修飾詞暖璧;修飾基礎(chǔ)數(shù)據(jù)類型時(shí),表示一個常量君旦,值不可變澎办,修飾指針類型變量時(shí),const關(guān)鍵字在左邊于宙,指針的地址不可變浮驳,指針指向的值可變悍汛,const關(guān)鍵字在右邊捞魁,指針的地址可變,指針指向的值不可變离咐;
- 宏定義:可以把常量谱俭,函數(shù)等聲明成宏奉件,在編譯時(shí)替換;
- static:修飾局部變量昆著,只分配一次內(nèi)存县貌,局部變量生命周期會延長到程序生命周期;修飾全局變量凑懂,改變?nèi)肿兞孔饔糜蛎汉郏o態(tài)全局變量只能在本文件內(nèi)訪問。
- extern:聲明外部變量接谨;B類中定義的全局變量摆碉,可以在A類中用extern聲明之后使用,不需要再導(dǎo)入B頭文件脓豪。
9巷帝、OC、C扫夜、C++楞泼、Swift混編
.m文件只識別OC語法和C語法;
.mm文件識別OC笤闯、C堕阔、C++語法;
.cpp識別C++颗味、C語法
- OC調(diào)用Swift印蔬,需要OC頭文件導(dǎo)入TargetName-Swift.h文件
- Swift調(diào)用OC,需要把OC頭文件加入TargetName-Bridging-Header.h頭文件里脱衙。
10侥猬、isa指針
實(shí)例對象的isa指針指向?qū)ο蟮念悾惱锇藢?shí)例對象可使用的屬性成員變量方法等所有信息捐韩。類的isa指針指向元類退唠,元類保存了類對象的方法和屬性等信息,元類的isa指針指向根元類荤胁,根元類的isa指針指向自己瞧预。
- 系統(tǒng)為NSObject對象分配16個字節(jié)的內(nèi)存,但是一般只占用8個字節(jié)仅政。
// 打印對象的地址
NSLog(@"%p", obj);
// 打印指針的地址
NSLog(@"%p", &obj);
11垢油、響應(yīng)者鏈和事件傳遞
- 事件傳遞:當(dāng)用戶觸摸屏幕時(shí),系統(tǒng)會把觸摸事件通過端口傳遞給前臺APP的UIApplication圆丹,由UIApplication傳遞給Window滩愁,window傳遞給最上層的視圖。事件的傳遞是由下到上辫封,由-hitTest:withEvent:判斷觸摸點(diǎn)在不在當(dāng)前view硝枉,如果在的話就遍歷子view廉丽,依次找到最上層的view。
- 響應(yīng)者:繼承自UIResponder的類都可以成為響應(yīng)者妻味。
- 響應(yīng)者鏈:由響應(yīng)者組成的事件響應(yīng)鏈條正压;當(dāng)一個事件傳遞給響應(yīng)者后,會判斷響應(yīng)者能不能處理事件责球,也就是有沒有實(shí)現(xiàn)-touchesBegan:withEvent:等系列方法或者是有手勢存在焦履,如果沒有就確定這個view不處理這次觸摸事件,事件會傳遞給父view(如果是Controller的view雏逾,會出遞給Controller)裁良,依次向下傳遞,直到UIApplication校套,如果都不能處理事件价脾,則事件會被廢棄。
12笛匙、block侨把、__weak、__block妹孙,以及對變量的捕獲原理
- block:本質(zhì)是一個對象秋柄,有isa指針,內(nèi)部封裝了一個函數(shù)以及函數(shù)的調(diào)用環(huán)境蠢正,可以在需要的時(shí)候執(zhí)行骇笔。
- __weak :一般用于block解循環(huán)引用。
- __block:一般用于block內(nèi)部修改外部變量值時(shí)嚣崭,對外部變量的修飾詞笨触。
- NSGlobalBlock:block內(nèi)部不捕獲外部局部變量,是全局block雹舀;
- NSStackBlock:block捕獲了外部局部變量芦劣,是棧block;
- NSMallocBlock:棧block進(jìn)行copy操作说榆,會被copy到堆上(block的copy虚吟、block作為函數(shù)返回值、block被賦值給強(qiáng)指針签财、block作為OC里面帶有usingBlock的函數(shù)參數(shù)串慰、block作為GCD函數(shù)參數(shù)時(shí),都會被copy到堆上)
為什么block要捕獲變量唱蒸?
- 函數(shù)內(nèi)部定義的block和當(dāng)前函數(shù)的作用域不同邦鲫,當(dāng)前函數(shù)內(nèi)定義的局部變量會在函數(shù)執(zhí)行結(jié)束時(shí)被釋放,但是block仍然有可能訪問變量油宜,所以需要捕獲變量到block內(nèi)部掂碱。
為什么block能捕獲變量怜姿?
- 因?yàn)閎lock對象內(nèi)部生成了對應(yīng)的變量屬性慎冤,所謂捕獲疼燥,就是block內(nèi)部持有這個變量。
為什么block內(nèi)部不能直接修改局部變量值蚁堤?
- 基本類型變量醉者,是值copy,外部局部變量和block內(nèi)部的變量已經(jīng)不是同一個變量披诗,所以不能修改撬即;
- 對象類型變量,被捕獲的是變量的指針呈队,是變量指針的copy剥槐;block內(nèi)部copy一份變量指針,指向?qū)ο蟮刂废艽荩@個指針和外部指針不是同一個了粒竖,自然不能修改。
- 全局變量:block內(nèi)部引用全局變量几于,是直接訪問蕊苗,不會發(fā)生捕獲。
- 局部變量-基本類型:捕獲基本類型是值copy沿彭,block保存了一份變量值到block內(nèi)部朽砰,
- 局部變量-對象類型:捕獲對象類型是指針copy,block內(nèi)部會生成一個對象類型的指針指向該對象喉刘,對象的引用計(jì)數(shù)會根據(jù)外部對象引用計(jì)數(shù)修飾詞(__strong瞧柔、__weak)等決定是否+1;
- 靜態(tài)變量:靜態(tài)變量的生命周期會持續(xù)到App退出睦裳,所以對靜態(tài)變量的捕獲是指針的傳遞非剃,block內(nèi)部直接訪問;
- __block修飾的變量:被__block修飾的局部變量推沸,會被包裝成一個__block結(jié)構(gòu)體备绽,它內(nèi)部持有指向局部變量的指針TestModel *model3,__Block_byref_model3_1 *__forwarding指向自己:
void *__isa;
__Block_byref_model3_1 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
TestModel *model3;
};
block在被copy到堆上時(shí)鬓催,__block結(jié)構(gòu)體同時(shí)被copy到堆上肺素,它的__forwarding指針指向被copy到堆上的結(jié)構(gòu)體內(nèi)存地址,block內(nèi)部通過__cself->model3.__forwarding->model3訪問原始變量的地址宇驾,從而修改值倍靡。
13、數(shù)據(jù)持久化
數(shù)據(jù)存儲的主要方式:
NSUserdefault:存儲輕量數(shù)據(jù)
NSKeyedArchiver:序列化存儲课舍,可以存儲實(shí)現(xiàn)NSCoding協(xié)議的model塌西;
Sqlite:建立數(shù)據(jù)庫存儲數(shù)據(jù)他挎;
CoreData:Apple特有的一種數(shù)據(jù)庫支持方案,apple自動建立了數(shù)據(jù)表和模型的關(guān)聯(lián)捡需,使用方式更加面向?qū)ο蟀旖埃臃奖恪?br>
KeyChin:鑰匙串存儲,一般存儲一些重要的站辉、保密要求高的輕量數(shù)據(jù)呢撞。
14、id饰剥、NSObject殊霞、instancetype、nil汰蓉、Nil绷蹲、NULL、NSNULL的區(qū)別?
id:可以指向任意類型的對象顾孽,不會做編譯時(shí)檢查祝钢,不會做類型轉(zhuǎn)換。
NSObject:指向任意NSObject子類對象岩齿,會做編譯時(shí)檢查太颤,會做類型轉(zhuǎn)換。
instancetype:只能作為方法的返回值盹沈,會做類型校驗(yàn)龄章。
nil:空實(shí)例對象。
Nil:空類對象.
NULL:空基本數(shù)據(jù)類型乞封。
NSNULL:在不能使用nil的時(shí)候做裙,表示一個空對象。
15肃晚、BOOL和bool
在64位操作系統(tǒng)或者ArmV7k后锚贱,BOOL其實(shí)就是bool
在32位系統(tǒng)中,BOOL是signer char关串,取值-128~127拧廊,當(dāng)BOOL a = 8960時(shí),超過一個字節(jié)晋修,會把8960轉(zhuǎn)化為二進(jìn)制0010 0011 0000 0000吧碾,取后八位0000 0000,也就是a = 0墓卦,會判斷出a為NO倦春。
另外下面的比較也會出問題,慎用 == YES:
if (c == YES) {
NSLog(@"c YES");
} else {
NSLog(@"c NO");
}
16、NSSet 睁本、NSArray尿庐、NSPointerArray、NSHashTable呢堰、NSDictionary抄瑟、NSMapTable、NSCache
NSSet:無序集合暮胧,只能存放對象锐借,會自動去重问麸,查詢元素速度很快往衷;
NSArray:有序集合,只能存放對象严卖,在內(nèi)存中是連續(xù)的席舍,增加刪除比較快;
NSPointerArray:有序集合哮笆,允許NULL元素加入集合来颤,可以使用weak修飾集合元素,而NSSet和NSArray對集合內(nèi)對象的必須是強(qiáng)引用的稠肘;
NSHashTable:無序集合福铅,可以使用weak修飾集合元素
NSDictionary:健值對,key必須遵循NSCopyding项阴,value為非空對象滑黔;
NSMapTable:類似NSDictionary,可以對key或value設(shè)置是否強(qiáng)引用环揽;
NSCache:健值存儲略荡,不會對key強(qiáng)引用,當(dāng)發(fā)生內(nèi)存警告歉胶,NSCache會自動清除緩存汛兜,NSCache線程安全,非常合適做緩存通今。
17粥谬、runtime
動態(tài)運(yùn)行時(shí),是OC語言的特性之一辫塌。runtime使OC的方法調(diào)用漏策,在編譯時(shí)不會去確定具體調(diào)用的方法,而是在運(yùn)行時(shí)動態(tài)查找執(zhí)行方法璃氢。
OC里面對象調(diào)用方法哟玷,其實(shí)是向這個對象發(fā)送消息,通過對象的isa指針找到對象的類,從類的方法列表里面查找方法巢寡,從而執(zhí)行喉脖。
runtime常見用法:
1、交換方法實(shí)現(xiàn)抑月,使已有類的方法有新的能力树叽。
2、動態(tài)添加方法
3谦絮、添加關(guān)聯(lián)屬性
4题诵、實(shí)現(xiàn)模型字典轉(zhuǎn)換
5、實(shí)現(xiàn)自動歸解檔
7层皱、消息轉(zhuǎn)發(fā)性锭,可以規(guī)避方法未找到的crash
18、進(jìn)程
在iOS中叫胖,一個APP啟動草冈,就是開啟一個進(jìn)程,一個進(jìn)程有單獨(dú)的內(nèi)存空間瓮增、系統(tǒng)資源怎棱、端口等,進(jìn)程可以開啟多個線程執(zhí)行任務(wù)绷跑,各線程共享進(jìn)程的資源拳恋。進(jìn)程間通信可以通過Port(端口)、URL Scheme砸捏、Keychain谬运、UIPasteboard(剪切板)、UIDocumentInterationController(共享文檔)带膜、AirDrop吩谦、UIActivityController(分享面板)、App Groups(系統(tǒng)分享)
19膝藕、多線程
多線程式廷,是同時(shí)開辟多個線程,并發(fā)執(zhí)行任務(wù)芭挽,提升性能的技術(shù)滑废。同一時(shí)間一個CPU核心只能處理一個線程,所謂的并發(fā)執(zhí)行袜爪,就是CPU快速在多個線程之間調(diào)度蠕趁,所呈現(xiàn)的同時(shí)執(zhí)行的假象,它的優(yōu)勢是充分利用多核處理器的優(yōu)勢辛馆,使多個任務(wù)可以在多核CPU中同時(shí)執(zhí)行俺陋,他的缺點(diǎn)是新線程會占用空間豁延,線程間切換會有時(shí)間開銷。
常見的多線程方案:
p_thread腊状、NSThread诱咏、GCD、NSOperation缴挖。
常見的多線程通信方案:
1袋狞、訪問同一個變量
2、通過- performSelect:
3映屋、線程間加鎖
4苟鸯、通過NSPort傳遞信息
p_thread:是一套C的接口,需要手動管理線程生命周期棚点,使用難度大早处;
NSThread:OC接口,使用簡單乙濒,多用于簡單的開啟線程執(zhí)行任務(wù)陕赃,不適合復(fù)雜的線程操作卵蛉,需要手動管理線程生命周期颁股,常見使用方式:
-performSelector: onThread: withObject: waitUntilDone:
-performSelectorOnMainThread: withObject: waitUntilDone:
GCD:一套C接口,能充分利用多核技術(shù)傻丝,不需要管理線程生命周期甘有,使用便捷
dispatch_sync:同步執(zhí)行任務(wù)
dispatch_async:異步執(zhí)行任務(wù)
dispatch_group_t:調(diào)度組,配合dispatch_group_async葡缰、dispatch_group_notify實(shí)現(xiàn)執(zhí)行完一組操作之后亏掀,再執(zhí)行接下來的操作。
dispatch_barrier_(a)sync:柵欄函數(shù)泛释,會等待barrier任務(wù)之前的任務(wù)執(zhí)行完之后滤愕,再執(zhí)行barrier提交的任務(wù)
dispatch_semaphore:信號量,一種鎖怜校,用于等待異步任務(wù)執(zhí)行結(jié)束后再執(zhí)行后續(xù)任務(wù)
dispatch_once_token:多用于創(chuàng)建單例
GCD取消任務(wù):只能取消未開始執(zhí)行的任務(wù)
通過dispatch_block_cancle取消加入GCD且未開始執(zhí)行的block
通過bool變量+return操作间影,使未執(zhí)行的block不再執(zhí)行。
NSOperation:apple對GCD封裝的一套面向?qū)ο蟮亩嗑€程接口茄茁,不需要管理線程生命周期魂贬,可以實(shí)現(xiàn)復(fù)雜的線程操作(添加線程間依賴等)
NSOptration是抽象類,只提供了接口裙顽,沒有類的實(shí)現(xiàn)付燥。使用NSOptration主要使用NSBlockOperation、NSInvocationOperation兩個子類愈犹,當(dāng)然也可以自定義NSOptration實(shí)現(xiàn)多線程操作键科,通過兩個子類創(chuàng)建任務(wù),添加到NSOperationQueue里面執(zhí)行。
-addDependency:添加線程間依賴
-cancle:取消未執(zhí)行的任務(wù)
-cancelAllOperations:取消所有未執(zhí)行的任務(wù)
線程安全:在多線程執(zhí)行任務(wù)時(shí)勋颖,有可能多個線程同時(shí)訪問同一個資源梆掸,并對資源做出修改,容易引起資源數(shù)據(jù)混亂牙言,造成程序運(yùn)行不可預(yù)測酸钦,所以需要保證線程安全。
加鎖:保證線程在訪問資源時(shí)咱枉,不會有其他線程同時(shí)操作這個資源
設(shè)置線程同步執(zhí)行:同步執(zhí)行任務(wù)卑硫,保證了對資源有序訪問。
自旋鎖:自旋鎖會忙等蚕断,也就是當(dāng)一個線程訪問一塊加鎖資源欢伏,線程不會休眠,會執(zhí)行while循環(huán)亿乳,直到資源解鎖
互斥鎖:線程會休眠硝拧,也就是當(dāng)一個線程訪問一塊加鎖資源,會休眠葛假,CPU可以調(diào)度其他線程執(zhí)行其他操作障陶,當(dāng)資源解鎖時(shí),通知該線程喚醒并開始執(zhí)行
死鎖:多個操作互相等待對方執(zhí)行完成聊训,才執(zhí)行自己抱究,導(dǎo)致任務(wù)卡住,造成死鎖带斑。
常見鎖:
OSSpinLock:自旋鎖鼓寺,iOS10.0后已被廢棄
os_unfair_lock:iOS10.0之后,用于取代OSSpinLock勋磕,并不會使線程忙等
pthread_mutex_t:互斥鎖
NSLock:apple對mutex的封裝
NSConditionLock:遞歸鎖(多次加鎖不會造成死鎖)妈候,apple對mutex的封裝
@ synchronized:apple對mutex的封裝
dispatch_semaphore:最常使用的鎖,性能也比較好
pthread_rwlock_t:讀寫鎖挂滓,當(dāng)多線程訪問同一塊資源時(shí)苦银,對讀操作不加鎖,對寫操作加鎖杂彭;也就是多個讀操作的線程會同時(shí)執(zhí)行墓毒,當(dāng)有線程進(jìn)行寫操作執(zhí)行時(shí)才進(jìn)行加鎖,其他線程讀操作和寫操作等待寫操作執(zhí)行完成亲怠,多用于IO操作文件讀寫時(shí)所计,提高了效率。
20团秽、runloop
runloop:是一個事件處理循環(huán)機(jī)制主胧,負(fù)責(zé)事件接收和分發(fā)叭首,是多線程的框架的基礎(chǔ)構(gòu)成。一個runloop對應(yīng)一個線程踪栋,對應(yīng)關(guān)系在一個全局字典里焙格,key為線程,value為runloop夷都,開啟線程時(shí)眷唉,并不會開啟runloop,當(dāng)?shù)谝淮潍@取runloop時(shí)囤官,runloop才被創(chuàng)建冬阳。
runloop的運(yùn)行模式:
NSDefaultRunLoopMode:默認(rèn)運(yùn)行模式,主線程在這種模式下運(yùn)行
UITrackingRunLoopMode:頁面滑動時(shí)的模式
NSRunLoopCommonModes:NSDefaultRunLoopMode+ UITrackingRunLoopMode
runloop運(yùn)行邏輯:
source0:非基于端口的事件源党饮,通常是用戶觸摸事件肝陪、select事件等,是app內(nèi)部生成的事件源刑顺,不基于端口傳遞氯窍。
source1:基于端口事件源,一般是系統(tǒng)間的通信蹲堂、網(wǎng)絡(luò)請求等狼讨,基于端口傳遞消息。
1贯城、通知observer即將進(jìn)入runloop
2熊楼、同時(shí)observe即將處理timer
3、通知observer即將處理source0
4能犯、處理source0
5、如有source1犬耻,且已經(jīng)準(zhǔn)備好踩晶,則進(jìn)入第9步
6、通知observe枕磁,即將休眠
7渡蜻、休眠中,等待喚醒(timer源時(shí)間到了计济,手動喚醒茸苇,source0事件源)
8、通知observe沦寂,即將被喚醒
9学密、處理喚醒時(shí)收到的消息(timer,source1)传藏,然后跳轉(zhuǎn)到第2步
10腻暮、通知observe彤守,即將退出runloop
常駐線程:
@interface WYYThread : NSThread
@end
@implementation WYYThread
- (void)dealloc {
NSLog(@"WYYThread - %s", __func__);
}
@end
@interface TestThread ()
@property (nonatomic, strong) WYYThread *thread;
@property (nonatomic, assign) BOOL thread_stop;
@end
@implementation TestThread
- (instancetype)init {
if (self = [super init]) {
self.thread_stop = NO;
__weak typeof(self) weakSelf = self;
self.thread = [[WYYThread alloc] initWithBlock:^{
[[NSRunLoop currentRunLoop] addPort:[NSPort new] forMode:NSDefaultRunLoopMode];
while (weakSelf != nil && !weakSelf.thread_stop) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
NSLog(@"runloop 結(jié)束");
}];
self.thread.name = @"TestThread";
[self.thread start];
}
return self;
}
- (void)addTask:(dispatch_block_t)block {
[self performSelector:@selector(takeTask:) onThread:self.thread withObject:block waitUntilDone:YES];
}
- (void)takeTask:(dispatch_block_t)block {
block();
}
- (void)takeStopTask {
self.thread_stop = YES;
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)stop {
[self performSelector:@selector(takeStopTask) onThread:self.thread withObject:nil waitUntilDone:YES];
}
- (void)dealloc {
NSLog(@"TestThread - %s", __func__);
[self stop];
}
@end
21、網(wǎng)絡(luò)相關(guān)
HTTP協(xié)議:
超文本傳輸協(xié)議哭靖,使用80端口具垫,是基于TCP/IP的應(yīng)用層協(xié)議,規(guī)定了客戶端和服務(wù)器之前傳輸數(shù)據(jù)的規(guī)則试幽,HTTP不只能傳輸文本筝蚕,可以傳輸任意類型數(shù)據(jù)。
常用方法
GET:用于向服務(wù)器請求數(shù)據(jù)铺坞,參數(shù)跟在URL后面饰及,有參數(shù)長度限制,明文傳遞數(shù)據(jù)
POST:用于向服務(wù)端提交數(shù)據(jù)康震,數(shù)據(jù)放在包體里燎含,理論上沒有參數(shù)大小限制,相比于GET會更安全腿短。
HEAD:類似GET屏箍,單數(shù)請求返回?cái)?shù)據(jù)里沒有包體,只有請求頭
DELETE:向服務(wù)器請求刪除數(shù)據(jù)
PUT:向服務(wù)器請求更新數(shù)據(jù)
特點(diǎn):
靈活:可以傳輸任意類型數(shù)據(jù)
無連接:一次鏈接只發(fā)送一次請求
無狀態(tài):不記錄請求狀態(tài)橘忱,斷聯(lián)需要重傳
聯(lián)接過程:
客戶端向服務(wù)端發(fā)起連接
服務(wù)端客戶端建立連接赴魁,客戶端向服務(wù)端請求數(shù)據(jù)
服務(wù)端響應(yīng)客戶端請求
客戶端收到請求,關(guān)閉連接
請求報(bào)文:
請求行:包含請求方式(Method)钝诚、請求URL颖御、HTTP版本號
請求頭:請求附加數(shù)據(jù),accept:客戶端接收的資源類型(如text/html)凝颇,content-length:數(shù)據(jù)長度等
請求體:請求數(shù)據(jù)
響應(yīng)報(bào)文:
響應(yīng)行:服務(wù)器返回的狀態(tài)內(nèi)容潘拱,HTTP版本號、狀態(tài)碼等
響應(yīng)頭:和請求頭類似
響應(yīng)體:具體的響應(yīng)數(shù)據(jù)
HTTPS:超文本傳輸安全協(xié)議拧略,使用443端口芦岂,是由HTTP+SSL組成,旨在解決HTTP傳輸不安全的問題垫蛆。
HTTPS連接過程:
客戶端向服務(wù)器請求連接
服務(wù)器申請CA證書禽最,發(fā)送證書包含公鑰給客戶端
客戶端通過根證書確認(rèn)服務(wù)器證書有效性,進(jìn)行身份確認(rèn)
客戶端生成對稱加密密鑰袱饭,通過公鑰加密川无,發(fā)送給服務(wù)器
服務(wù)器收到加密密鑰,使用私鑰解密對稱加密的密鑰
客戶端和服務(wù)器使用對稱加密密鑰進(jìn)行數(shù)據(jù)傳輸
對稱加密:加密解密使用同一密鑰虑乖,加解密速度很快懦趋,使用很廣泛,常見有AES算法决左,DES算法愕够,3DES算法等
非對稱加密:生成公鑰私鑰一對密鑰走贪,加解密使用不同的密鑰,私鑰需要嚴(yán)格保存不能泄漏惑芭。常見RAS算法坠狡。
TCP:傳輸控制協(xié)議
面向連接可靠的基于字節(jié)流的傳輸層控制協(xié)議,是為了在不可靠的網(wǎng)絡(luò)中傳輸局?jǐn)?shù)據(jù)定義的一套協(xié)議遂跟,有三次握手建立連接逃沿,有確認(rèn)、窗口幻锁、重傳凯亮、擁塞控制機(jī)制,傳輸完成后哄尔,會斷開連接(四次揮手)節(jié)省資源
第一次握手:客戶端->服務(wù)器 發(fā)送SYN標(biāo)志位 序列號為X(隨機(jī)生成的假消,標(biāo)志數(shù)據(jù)傳輸序列的數(shù)字)的數(shù)據(jù)包,請求建立連接
第二次握手:服務(wù)端收到客戶端SYN數(shù)據(jù)包岭接,想客戶端發(fā)送SYN+ACK數(shù)據(jù)包富拗,SYN包中有服務(wù)器生成的隨機(jī)序列號Y,ACK包序列號為X+1鸣戴,表示服務(wù)端收到客戶端請求啃沪,同意建立連接。
第三次握手:客戶端收到服務(wù)器SYN+ACK包窄锅,向服務(wù)器發(fā)送ACK包创千,序列號為Y+1,聯(lián)接建立入偷,開始數(shù)據(jù)傳輸
數(shù)據(jù)傳輸:TCP數(shù)據(jù)會被分成TCP段追驴,包含固定長度的頭部,和數(shù)據(jù)部分盯串,頭部數(shù)據(jù)包含源端口號氯檐,目標(biāo)端口號,序列號体捏,確認(rèn)應(yīng)答號,標(biāo)志位等信息糯崎。
序列號:發(fā)送方在發(fā)送數(shù)據(jù)時(shí)几缭,對每個字節(jié)數(shù)據(jù)進(jìn)行編碼,序列號就是該段數(shù)據(jù)第一個字節(jié)的編碼沃呢,接收方通過該序列號對接收到的TCP段進(jìn)行重組年栓,確保數(shù)據(jù)完整性和順序性。
確認(rèn)應(yīng)答號:接收方在收到TCP段后薄霜,會向發(fā)送方發(fā)送ACK包某抓,確認(rèn)應(yīng)答號為接收方期望接收的下一個序列號的TCP段纸兔,發(fā)送方根據(jù)收到的確認(rèn)應(yīng)答號確認(rèn)接收方有沒有正確接收數(shù)據(jù),如果沒有收到否副,或確認(rèn)應(yīng)答號不對汉矿,則觸發(fā)重傳。
滑動窗口機(jī)制:在接收方和發(fā)送方之間維護(hù)緩沖區(qū)备禀,暫存發(fā)送方已發(fā)送洲拇,接收方未應(yīng)答的TCP段,發(fā)送方可以連續(xù)發(fā)送多個TCP段曲尸,隨著接收方不斷接收確認(rèn)數(shù)據(jù)赋续,窗口向前滑動,發(fā)送發(fā)可以連續(xù)發(fā)送新的數(shù)據(jù)另患。
第一次揮手:客戶端完成數(shù)據(jù)傳輸之后纽乱,向服務(wù)端發(fā)送FIN數(shù)據(jù)包,請求關(guān)閉連接
第二次揮手:服務(wù)器收到客戶端FIN數(shù)據(jù)包昆箕,向客戶端發(fā)送ACK數(shù)據(jù)包鸦列,表示已知客戶端數(shù)據(jù)發(fā)送完畢,但此時(shí)服務(wù)器數(shù)據(jù)有可能沒有發(fā)送完畢为严,則繼續(xù)發(fā)送编丘。
第三次揮手:服務(wù)端數(shù)據(jù)發(fā)送完畢,向客戶端發(fā)送FIN數(shù)據(jù)包挽拔,請求關(guān)閉連接
第四次揮手:客戶端向服務(wù)器發(fā)送ACK包吼拥,連接關(guān)閉。
UDP:數(shù)據(jù)報(bào)協(xié)議
對應(yīng)TCP夕吻,UDP是非連接的協(xié)議诲锹,不與對方建立連接,直接把數(shù)據(jù)發(fā)送過去涉馅,適合對及時(shí)性要求高归园,數(shù)據(jù)量小,且對質(zhì)量要求不高的場景稚矿。
Socket:基于對TCP/IP的封裝庸诱,提供一套接口,用于兩個程序通過雙向連接傳輸數(shù)據(jù)晤揣。也就是常說的長連接桥爽。
心跳:長連接中,用于保證長連接有效的機(jī)制昧识,客戶端向服務(wù)器發(fā)送心跳包钠四,收到服務(wù)器響應(yīng)確認(rèn)長連接有效。
DNS:域名解析服務(wù)跪楞,用于域名和IP地址的映射缀去,是互聯(lián)網(wǎng)提供的一種服務(wù)侣灶。
DNS劫持:域名劫持,攔截域名解析請求缕碎,返回假的域名地址或使域名無法訪問褥影。
網(wǎng)絡(luò)七層模型:
應(yīng)用層:網(wǎng)絡(luò)服務(wù)與用戶的接口,有HTTP協(xié)議
表示層:數(shù)據(jù)的表示阎曹,安全伪阶,壓縮等
會話層:本地主機(jī)與遠(yuǎn)程主機(jī)連接、管理处嫌、終止
傳輸層:定義數(shù)據(jù)傳輸?shù)膮f(xié)議栅贴、端口等,以及流控和差錯校驗(yàn)熏迹。TCP檐薯、UDP等協(xié)議
網(wǎng)絡(luò)層:進(jìn)行邏輯地址尋址,實(shí)現(xiàn)不同網(wǎng)絡(luò)之間的路徑選擇
數(shù)據(jù)鏈路層:建立邏輯連接注暗、進(jìn)行硬件地址尋址坛缕、差錯校驗(yàn) [2] 等功能
物理層:建立、維護(hù)捆昏、斷開物理連接
斷點(diǎn)續(xù)傳:
使用HTTP:利用HTTP頭部有Range字段赚楚,請求的數(shù)據(jù)的具體部分,然后拼接在已請求到的數(shù)據(jù)之后骗卜。
22宠页、性能優(yōu)化
畫面卡頓:iOS屏幕刷新頻率是一秒鐘60幀,也就是16.7ms刷新一次屏幕寇仓,而屏幕上一幀畫面是由CPU和GPU協(xié)作完成的举户,CPU負(fù)責(zé)對象的創(chuàng)建、布局計(jì)算等數(shù)據(jù)處理遍烦,GPU負(fù)責(zé)把CPU準(zhǔn)備好的數(shù)據(jù)進(jìn)行渲染俭嘁,渲染完成之后,會把畫面放到幀緩沖區(qū)服猪。那么當(dāng)CPU處理數(shù)據(jù)時(shí)間占用過多供填,或者GPU渲染耗時(shí)過多,沒有在16.7ms之內(nèi)把渲染好的數(shù)據(jù)放到幀緩沖區(qū)罢猪,就會出現(xiàn)掉幀捕虽,就會造成畫面卡頓。
離屏渲染:iOS是雙緩存機(jī)制坡脐,有前幀緩存和后幀緩存,GPU會把需要顯示的屏幕數(shù)據(jù)渲染好放進(jìn)前幀緩存房揭,提供給視頻讀取器讀取备闲,會把這一幀之后需要顯示的數(shù)據(jù)渲染在后幀緩存晌端,當(dāng)接收到Vsync信號后,會把視頻讀取器指向前幀緩存的指針指向后幀緩存恬砂,前幀緩存的數(shù)據(jù)被丟棄咧纠,變?yōu)楹髱彺妗PU在渲染時(shí)遵循“畫家算法”泻骤,由遠(yuǎn)及近渲染畫面漆羔。當(dāng)我們設(shè)置光柵化(shouldRasterize)、添加遮罩(mask)狱掂、圓角(coreRadius)演痒、陰影(shadow)等時(shí),由于前幀緩存使用過之后數(shù)據(jù)已經(jīng)沒了趋惨,我們又要對這些數(shù)據(jù)進(jìn)行設(shè)置鸟顺,所以只好再開辟一塊緩存區(qū),用于操作已經(jīng)渲染的數(shù)據(jù)器虾,當(dāng)這些操作做完后讯嫂,再把渲染好的數(shù)據(jù)放入離屏幀緩沖區(qū)用于顯示。這種開辟新的非屏幕當(dāng)前緩沖區(qū)來渲染數(shù)據(jù)的方式兆沙,就是離屏渲染欧芽。
離屏渲染觸發(fā)卡頓:1、創(chuàng)建新的幀緩沖區(qū)有資源消耗葛圃;2千扔、從當(dāng)前屏幕緩沖區(qū)切換到離屏緩沖區(qū),顯示完之后需要再切換回當(dāng)前屏幕幀緩沖區(qū)装悲,多次上下文切換浪費(fèi)時(shí)間昏鹃。
性能優(yōu)化:
CPU-優(yōu)化:
1、使用Table View的cell重用機(jī)制
2诀诊、Table View高度做緩存洞渤,因?yàn)楫?dāng)滑動時(shí),highForRow會頻繁調(diào)用属瓣,緩存高度避免重復(fù)計(jì)算
3载迄、減少視圖層級,減少容易引起離屏渲染的操作
4抡蛙、Table View刷新不要盲目的調(diào)用reloadData护昧,有時(shí)候只刷新一個cell就行
5、當(dāng)view不需要響應(yīng)事件時(shí)粗截,盡量用Layer顯示圖像
6惋耙、在布局變動時(shí),盡量提前計(jì)算好所有布局,統(tǒng)一提交改動绽榛,不要一個屬性一個屬性的改動
7湿酸、AutoLayout最終會轉(zhuǎn)化為frame,所以會比frame更慢
8灭美、盡量把耗時(shí)操作放在子線程
GPU-優(yōu)化:
1推溃、避免短時(shí)間內(nèi)顯示大量圖片,合成一張顯示
2届腐、大圖片要分片展示
3铁坎、減少視圖數(shù)量和層級
4、減少透明圖層
5犁苏、減少離屏渲染
離屏渲染-優(yōu)化:
1硬萍、使用UIBezierPath畫圓角,用shadowPath指定陰影效果路徑傀顾,避免裁剪等方式
2襟铭、設(shè)置layer的opaque為YES,避免復(fù)雜圖層的合成
3短曾、盡量不使用包含透明通道(alpha)的圖片
4寒砖、最好讓美工做出相應(yīng)效果(陰影、圓角)的圖片
APP 啟動過程:
dyld:加載Mach-O文件嫉拐,連接動態(tài)庫
runtime:當(dāng)dyld完成所有可執(zhí)行文件加載哩都,動態(tài)庫連接之后,會通知runtime進(jìn)行下一步
調(diào)用map_images進(jìn)行可執(zhí)行文件的解析和處理
在load_images中調(diào)用call_load_methods婉徘,執(zhí)行所有類和分類的+load方法
進(jìn)行各種Objc結(jié)構(gòu)的初始化(注冊O(shè)bjc類漠嵌,初始化類對象)
調(diào)用C++靜態(tài)初始化器和attribute((constructor))修飾的函數(shù)
至此,可執(zhí)行文件周所有的符號(class盖呼、protocol儒鹿、IMP、selector等)都已經(jīng)加載完畢
main:初始化工作完成几晤,開始調(diào)用main函數(shù)约炎,UIApplicationMain函數(shù),APPDelegate的application:didFinishLaunchingWithOptions:函數(shù)蟹瘾,至此APP啟動完成
APP啟動優(yōu)化:
減少動態(tài)庫
減少類圾浅,分類,方法等
swift盡量用struct
+load 方法入無必要憾朴,放在+initialize中
application:didFinishLaunchingWithOptions:只做必要的工作狸捕,其他的工作可以等啟動完成后再做
23、常見三方庫
SDWebImage
三個核心類:SDWebImageManager众雷、SDImageCache灸拍、SDImageDownloader
當(dāng)加載圖片時(shí)做祝,會由SDWebImageManager執(zhí)行l(wèi)oadImageWithUrl:
首先由SDImageCache在內(nèi)存緩存中找,找到則回調(diào)顯示圖片株搔;
未找到則去磁盤緩存中找剖淀,找到的話,就把圖片緩存到內(nèi)存中纤房,再回調(diào)顯示圖片;
未找到則由SDImageDownloader開始下載圖片翻诉,下載完成后炮姨,則緩存到內(nèi)存和磁盤中,回調(diào)顯示圖片碰煌。
緩存是以圖片URL的MD5值為key舒岸,圖片為Value
SDImageDownloader的最大并發(fā)數(shù)為6
超時(shí)時(shí)間為15s
最大緩存時(shí)長為7天
AFNetworking
2.0是對NSURLConnection的封裝,沒用過
3.0是對NSURLSession的封裝
核心架構(gòu):
URLSession:進(jìn)行網(wǎng)絡(luò)通信
Serialization:進(jìn)行序列化操作
Reachability:網(wǎng)絡(luò)狀態(tài)監(jiān)聽
Security:證書等安全認(rèn)證
UIKit:對UI控件的擴(kuò)展