了解hash的重要性
在iOS開發(fā)中 隨處可見hash的身影,hash對于iOS開發(fā)起到了支撐的作用言缤。
下圖是部分具體應(yīng)用之處,圖片較為模糊,下面會每一個(gè)點(diǎn)的去介紹岔帽,分析其中的原理。
對于iOS 開發(fā)人員來講导绷,雖然我們處于應(yīng)用層的開發(fā)犀勒。所使用的技術(shù)已經(jīng)是高度封裝的API.對于我們來說,純調(diào)用接口交互妥曲,和用戶交互成為了移動端開發(fā)人員主要的工作任務(wù)贾费。對于算法、數(shù)據(jù)結(jié)構(gòu)檐盟、通信協(xié)議褂萧、文件系統(tǒng)、驅(qū)動等葵萎。雖然工作中沒有人會過多的去質(zhì)問這個(gè)程序的底層實(shí)現(xiàn)方案箱玷。俗話說的好,學(xué)而不思則罔陌宿,思而不學(xué)則怠锡足。凡事知其然必要知其所以然。才能更好的運(yùn)用所掌握 的技能壳坪。從而游刃有余舶得,而事半功倍。話不多說爽蝴,下面詳細(xì)介紹下hash中具體的使用沐批。
1.1、關(guān)聯(lián)對象的實(shí)現(xiàn)原理:
關(guān)聯(lián)對象是什么蝎亚?關(guān)聯(lián)對象說起來九孩,還的追溯到runtime底層的C代碼和匯編代碼。
是利用運(yùn)行時(shí)機(jī)制.給對象動態(tài)增添屬性成員變量的機(jī)制发框。術(shù)語就是AssocateObject .采用的便是hash表進(jìn)行的數(shù)據(jù)處理躺彬。是利用的hash表嵌套hash表的數(shù)據(jù)存儲結(jié)構(gòu)。
簡單來說就是根據(jù)對象從從第一個(gè)HashMap中取出存儲對象所有關(guān)聯(lián)對象的第二個(gè)HashMap,然后根據(jù)屬性名從第二個(gè)HashMap中取出屬性對應(yīng)的值和策略梅惯。
設(shè)計(jì)關(guān)聯(lián)對象的初衷是宪拥,通過傳入對象+屬性名字,就可以找到屬性值铣减。方案設(shè)計(jì)好后她君,查找一個(gè)對象的關(guān)聯(lián)對象的基本步驟:
1.已知條件一:對象,因此引出第一個(gè)HashMap,用一個(gè)能唯一代表對象的值作為key,用存儲對象的所有關(guān)聯(lián)對象的結(jié)構(gòu)(值+策略)作為value.
2.已知條件二:屬性名字,因此引出第二個(gè)HashMap,用屬性名字作為key.用屬性名字對應(yīng)的結(jié)構(gòu)(值+策略)作為value.
1.2葫哗、weak實(shí)現(xiàn)原理:
weak采用的是一個(gè)全局的HashMap嵌套數(shù)組的結(jié)構(gòu)存儲數(shù)據(jù)的缔刹。銷毀對象(weak指針指向的對象)的時(shí)候球涛,根據(jù)對象從HashMap中找到存放所有指向該對象的weak指針的數(shù)組,然后將數(shù)組中的所有元素(weak指針)都置為nil.
weak最大特點(diǎn)就是在銷毀對象的時(shí)候校镐,自動置為nil,減少訪問野指針的風(fēng)險(xiǎn)亿扁。這也是設(shè)計(jì)weak的初衷。方案設(shè)計(jì)實(shí)現(xiàn)好后灭翔,weak指針置nil的基本步驟:
-1魏烫、對象dealloc的時(shí)候,從全局的HashMap中肝箱,根據(jù)一個(gè)唯代表對象的值作為 key,找到存儲所有志向該對象的weak指針數(shù)組哄褒。
-2、將數(shù)組中的所有元素都置為nil
蘋果對于weak的實(shí)現(xiàn)其實(shí)類似于通知的實(shí)現(xiàn)煌张,指明誰(weak指針)要監(jiān)聽誰(賦值對象)什么事件(dealloc操作)執(zhí)行什么操作(置nil).
1.3呐赡、KVO實(shí)現(xiàn)使用的基本數(shù)據(jù)結(jié)構(gòu)
比較復(fù)雜,一個(gè)對象可以被n個(gè)對象觀察骏融,一個(gè)對象的n個(gè)屬性又可以被n個(gè)對像觀察链嘀。
1.4、iOS App簽名的原理
通俗來說就是: 一致性哈希算法 + 非對稱加解密算法档玻。
1.5怀泊、對象引用計(jì)數(shù)的存儲位置
if 對象支持TaggedPointer {
return 直接將對象的指針值作為引用計(jì)數(shù)返回
}
else if 設(shè)備是64位環(huán)境 && Objective-C2.0 {
return 對象isa指針的一部分空間(bits_extra_rc)
}
else {
return hash表
}
1.6、Runloop與線程的存儲關(guān)系
線程和Runloop之間是--(子線程可以沒有)對應(yīng)的误趴,其關(guān)系是保存在一個(gè)全局的dictionary里霹琼。線程創(chuàng)建時(shí)并沒有Runloop,如果你不主動獲取,那么就一直沒有凉当。Runloop的創(chuàng)建是發(fā)生在第一次獲取時(shí)枣申,Runloop的銷毀是發(fā)生在線程結(jié)束時(shí)。你只能在一個(gè)線程的內(nèi)部獲取其 Runloop(主線程外)看杭。
1.7忠藤、NSDictionary的原理:
這里說到NSDictionary的原理,就要先大體了解介紹下hashMap的原理楼雹。
hashMap通過 拉鏈法和開放定址線性探測發(fā) 來解決哈希沖突模孩。這里Apple都是用了的。具體使用哪一種解決方法是要根據(jù)存儲數(shù)據(jù)的生命周期和特性決定的烘豹。
-@synchronized使用的是拉鏈法瓜贾。拉鏈法多用于存儲解決的數(shù)據(jù)是通用類型,能夠被反復(fù)利用携悯,就像@synchronized存儲的是鎖是一種無業(yè)務(wù)的實(shí)現(xiàn)結(jié)構(gòu),程序運(yùn)行多個(gè)對象使用同一個(gè)鎖的概率相當(dāng)高筷笨,有效的節(jié)省了內(nèi)存憔鬼。
-weak對象associateObject采用的是開發(fā)定址性探測法龟劲。開放定址探測法用于存儲的數(shù)據(jù)是臨時(shí)的,用完盡量釋放轴或,就像associateObject,weak.
NSDictionary的存儲過程:
1昌跌、通過方法 - (void)setObject:(id)anObject forKey:(id)key;可以看出key必須遵守NScopy協(xié)議,也即是說NSDictionary的key是copy一份新的照雁,而value是淺拷貝的蚕愤。
2、不過這還不夠饺蚊,key還必須要繼承NSObject萍诱,并且重寫-(NSUInteger)hash和-(Bool)isequal:(id )object兩個(gè)方法。第一個(gè)函數(shù)用于計(jì)算hash值污呼,第二個(gè)函數(shù)用于判斷當(dāng)哈希值相同的時(shí)候value是否相同(解決hash沖突)裕坊。