KVO原理及自定義KVO
-
KVO原理
我們注冊(cè)監(jiān)聽(tīng)的時(shí)候,會(huì)對(duì)注冊(cè)者動(dòng)態(tài)的創(chuàng)建一個(gè)子類對(duì)象变隔,然后底層找方法的的isa指針就變成指向新創(chuàng)建的子類對(duì)象。當(dāng)改變注冊(cè)對(duì)象某個(gè)屬性的時(shí)候,就重寫(xiě)屬性的set方法來(lái)進(jìn)行監(jiān)聽(tīng)。 -
總結(jié)自定義一個(gè)KVO思路:
1.自定義一個(gè)類碾局,繼承 [self class]的一個(gè)子類
2.重寫(xiě)父類的屬性setter方法
3.調(diào)用observeValueForKeyPath:ofObject:change:context:方法,回調(diào)到ViewController中去奴艾。
具體原理及自定義KVO詳見(jiàn):https://blog.csdn.net/u014247354/article/details/78403567
消息轉(zhuǎn)發(fā)機(jī)制原理
消息轉(zhuǎn)發(fā)是在運(yùn)行時(shí)進(jìn)行的净当,大致分為兩個(gè)階段:第一階段是先檢查接收者,看是否能通過(guò)runtime動(dòng)態(tài)添加一個(gè)方法,來(lái)處理這個(gè)unknown selector的消息像啼;第二階段就是完整的消息轉(zhuǎn)發(fā)機(jī)制俘闯,首先會(huì)先查看有沒(méi)有其它對(duì)象能夠處理該消息,如果沒(méi)有埋合,就把該消息的全部信息封裝到NSInvocation對(duì)象中备徐,看那個(gè)對(duì)象能否處理萄传,如果還無(wú)法處理甚颂,就查看繼承樹(shù)中的類是否能夠處理該消息,如果到NSObject之前都無(wú)法處理該消息秀菱,那么最后就會(huì)調(diào)用NSObject類的doesNotRecognizeSelector方法來(lái)拋出異常振诬,表明調(diào)用的方法不存在。
具體轉(zhuǎn)發(fā)機(jī)制詳見(jiàn):https://www.cnblogs.com/fishbay/p/7216197.html?utm_source=itdadao&utm_medium=referral
說(shuō)說(shuō)你理解weak屬性
-
weak實(shí)現(xiàn)原理
Runtime維護(hù)了一個(gè)weak表衍菱,用于存儲(chǔ)指向某個(gè)對(duì)象的所有weak指針赶么。weak表其實(shí)是一個(gè)hash(哈希)表,Key是所指對(duì)象的地址脊串,Value是weak指針的地址(這個(gè)地址的值是所指對(duì)象的地址)數(shù)組辫呻。
1、初始化時(shí):runtime會(huì)調(diào)用objc_initWeak函數(shù)琼锋,初始化一個(gè)新的weak指針指向?qū)ο蟮牡刂贰?br> 2放闺、添加引用時(shí):objc_initWeak函數(shù)會(huì)調(diào)用 objc_storeWeak() 函數(shù), objc_storeWeak() 的作用是更新指針指向缕坎,創(chuàng)建對(duì)應(yīng)的弱引用表怖侦。
3、釋放時(shí)谜叹,調(diào)用clearDeallocating函數(shù)匾寝。clearDeallocating函數(shù)首先根據(jù)對(duì)象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil荷腊,最后把這個(gè)entry從weak表中刪除艳悔,最后清理對(duì)象的記錄。 -
追問(wèn)的問(wèn)題:
1.實(shí)現(xiàn)weak后女仰,為什么對(duì)象釋放后會(huì)自動(dòng)為nil猜年?
runtime 對(duì)注冊(cè)的類, 會(huì)進(jìn)行布局董栽,對(duì)于 weak 對(duì)象會(huì)放入一個(gè) hash 表中码倦。 用 weak 指向的對(duì)象內(nèi)存地址作為 key,當(dāng)此對(duì)象的引用計(jì)數(shù)為 0 的時(shí)候會(huì) dealloc锭碳,假如 weak 指向的對(duì)象內(nèi)存地址是 a 袁稽,那么就會(huì)以 a 為鍵, 在這個(gè) weak 表中搜索擒抛,找到所有以 a 為鍵的 weak 對(duì)象推汽,從而設(shè)置為 nil 补疑。
2.當(dāng)weak引用指向的對(duì)象被釋放時(shí),又是如何去處理weak指針的呢歹撒?
1莲组、調(diào)用objc_release
2、因?yàn)閷?duì)象的引用計(jì)數(shù)為0暖夭,所以執(zhí)行dealloc
3锹杈、在dealloc中,調(diào)用了_objc_rootDealloc函數(shù)
4迈着、在_objc_rootDealloc中竭望,調(diào)用了object_dispose函數(shù)
5、調(diào)用objc_destructInstance
6裕菠、最后調(diào)用objc_clear_deallocating,詳細(xì)過(guò)程如下:
a. 從weak表中獲取廢棄對(duì)象的地址為鍵值的記錄
b. 將包含在記錄中的所有附有 weak修飾符變量的地址咬清,賦值為 nil
c. 將weak表中該記錄刪除
d. 從引用計(jì)數(shù)表中刪除廢棄對(duì)象的地址為鍵值的記錄
假如Controller太臃腫,如何優(yōu)化奴潘?
1.將網(wǎng)絡(luò)請(qǐng)求抽象到單獨(dú)的類中
2.將界面的封裝抽象到專門(mén)的類中
3.構(gòu)造 ViewModel
4.專門(mén)構(gòu)造存儲(chǔ)類
項(xiàng)目中網(wǎng)絡(luò)層如何做安全處理旧烧?
1、盡量使用https
https可以過(guò)濾掉大部分的安全問(wèn)題画髓。https在證書(shū)申請(qǐng)掘剪,服務(wù)器配置愕秫,性能優(yōu)化隧熙,客戶端配置上都需要投入精力,所以缺乏安全意識(shí)的開(kāi)發(fā)人員容易跳過(guò)https碾阁,或者拖到以后遇到問(wèn)題再優(yōu)化愚墓。https除了性能優(yōu)化麻煩一些以外其他都比想象中的簡(jiǎn)單予权,如果沒(méi)精力優(yōu)化性能,至少在注冊(cè)登錄模塊需要啟用https浪册,這部分業(yè)務(wù)對(duì)性能要求比較低扫腺。
2、不要傳輸明文密碼
不知道現(xiàn)在還有多少app后臺(tái)是明文存儲(chǔ)密碼的村象。無(wú)論客戶端笆环,server還是網(wǎng)絡(luò)傳輸都要避免明文密碼,要使用hash值厚者≡炅樱客戶端不要做任何密碼相關(guān)的存儲(chǔ),hash值也不行库菲。存儲(chǔ)token進(jìn)行下一次的認(rèn)證账忘,而且token需要設(shè)置有效期,使用refresh token去申請(qǐng)新的token。
3鳖擒、Post并不比Get安全
事實(shí)上溉浙,Post和Get一樣不安全,都是明文蒋荚。參數(shù)放在QueryString或者Body沒(méi)任何安全上的差別戳稽。在Http的環(huán)境下,使用Post或者Get都需要做加密和簽名處理期升。
4惊奇、不要使用301跳轉(zhuǎn)
301跳轉(zhuǎn)很容易被Http劫持攻擊。移動(dòng)端http使用301比桌面端更危險(xiǎn)吓妆,用戶看不到瀏覽器地址赊时,無(wú)法察覺(jué)到被重定向到了其他地址吨铸。如果一定要使用行拢,確保跳轉(zhuǎn)發(fā)生在https的環(huán)境下,而且https做了證書(shū)綁定校驗(yàn)诞吱。
5舟奠、http請(qǐng)求都帶上MAC
所有客戶端發(fā)出的請(qǐng)求,無(wú)論是查詢還是寫(xiě)操作房维,都帶上MAC(Message Authentication Code)沼瘫。MAC不但能保證請(qǐng)求沒(méi)有被篡改(Integrity),還能保證請(qǐng)求確實(shí)來(lái)自你的合法客戶端(Signing)咙俩。當(dāng)然前提是你客戶端的key沒(méi)有被泄漏耿戚,如何保證客戶端key的安全是另一個(gè)話題。MAC值的計(jì)算可以簡(jiǎn)單的處理為hash(request params+key)阿趁。帶上MAC之后膜蛔,服務(wù)器就可以過(guò)濾掉絕大部分的非法請(qǐng)求。MAC雖然帶有簽名的功能脖阵,和RSA證書(shū)的電子簽名方式卻不一樣皂股,原因是MAC簽名和簽名驗(yàn)證使用的是同一個(gè)key,而RSA是使用私鑰簽名命黔,公鑰驗(yàn)證呜呐,MAC的簽名并不具備法律效應(yīng)。
6悍募、http請(qǐng)求使用臨時(shí)密鑰
高延遲的網(wǎng)絡(luò)環(huán)境下蘑辑,不經(jīng)優(yōu)化https的體驗(yàn)確實(shí)會(huì)明顯不如http。在不具備https條件或?qū)W(wǎng)絡(luò)性能要求較高且缺乏https優(yōu)化經(jīng)驗(yàn)的場(chǎng)景下坠宴,http的流量也應(yīng)該使用AES進(jìn)行加密洋魂。AES的密鑰可以由客戶端來(lái)臨時(shí)生成,不過(guò)這個(gè)臨時(shí)的AES key需要使用服務(wù)器的公鑰進(jìn)行加密,確保只有自己的服務(wù)器才能解開(kāi)這個(gè)請(qǐng)求的信息忧设,當(dāng)然服務(wù)器的response也需要使用同樣的AES key進(jìn)行加密刁标。由于http的應(yīng)用場(chǎng)景都是由客戶端發(fā)起,服務(wù)器響應(yīng)址晕,所以這種由客戶端單方生成密鑰的方式可以一定程度上便捷的保證通信安全膀懈。
7、AES使用CBC模式
不要使用ECB模式谨垃,記得設(shè)置初始化向量启搂,每個(gè)block加密之前要和上個(gè)block的秘文進(jìn)行運(yùn)算。
main()之前的過(guò)程有哪些刘陶?
1胳赌、dyld 開(kāi)始將程序二進(jìn)制文件初始化
2、交由ImageLoader 讀取 image匙隔,其中包含了我們的類疑苫,方法等各種符號(hào)(Class、Protocol 纷责、Selector捍掺、 IMP)
3、由于runtime 向dyld 綁定了回調(diào)再膳,當(dāng)image加載到內(nèi)存后挺勿,dyld會(huì)通知runtime進(jìn)行處理
4、runtime 接手后調(diào)用map_images做解析和處理
5喂柒、接下來(lái)load_images 中調(diào)用call_load_methods方法不瓶,遍歷所有加載進(jìn)來(lái)的Class,按繼承層次依次調(diào)用Class的+load和其他Category的+load方法
6灾杰、至此 所有的信息都被加載到內(nèi)存中
7蚊丐、最后dyld調(diào)用真正的main函數(shù)
注意:dyld會(huì)緩存上一次把信息加載內(nèi)存的緩存,所以第二次比第一次啟動(dòng)快一點(diǎn)
數(shù)據(jù)持久化方式
1吭露、NSUserDefaults
優(yōu)點(diǎn):簡(jiǎn)單易用,不需要我們?nèi)?chuàng)建文件,數(shù)據(jù)會(huì)直接存儲(chǔ)在沙盒內(nèi)prefrences文件夾下的plist文件中
缺點(diǎn):不能存儲(chǔ)自定義的過(guò)于復(fù)雜的對(duì)象
所以,我們一般用來(lái)存儲(chǔ)個(gè)人的偏好設(shè)置,存儲(chǔ)本地登陸的賬號(hào)密碼,判斷用戶是否第一次啟動(dòng)程序等這些簡(jiǎn)單的少量數(shù)據(jù).
2吠撮、簡(jiǎn)單對(duì)象文件讀寫(xiě)
優(yōu)點(diǎn):易用性強(qiáng),對(duì)于系統(tǒng)提供的基礎(chǔ)類型NSString,NSArray,NSDictionary,NSData可以根據(jù)文件路徑可以借助系統(tǒng)提供的方法直接進(jìn)行數(shù)據(jù)的本地存儲(chǔ).
缺點(diǎn):只能存儲(chǔ)系統(tǒng)提供的四種基本類型,不能進(jìn)行我們自定義的對(duì)象進(jìn)行持久化; 新的數(shù)據(jù)會(huì)將之前的數(shù)據(jù)進(jìn)行覆蓋,限定了我們也是只能進(jìn)行少量數(shù)據(jù)的存儲(chǔ).
所以,我們一般用于存儲(chǔ)系統(tǒng)提供的基本類型的小量存儲(chǔ),不適合大量數(shù)據(jù)的存儲(chǔ).
3、復(fù)雜對(duì)象文件讀寫(xiě)(歸檔與反歸檔)
優(yōu)點(diǎn):易用性強(qiáng),最突出的是可以將復(fù)雜的對(duì)象寫(xiě)入文件,可以歸檔集合類
缺點(diǎn):數(shù)據(jù)的存儲(chǔ)其實(shí)原理和簡(jiǎn)單對(duì)象的寫(xiě)入原理相同,也會(huì)進(jìn)行舊數(shù)據(jù)的覆蓋. 而且隨著對(duì)象量的增加工作量會(huì)隨之增加.
所以,我們一般用來(lái)對(duì)存儲(chǔ)少量的復(fù)雜對(duì)象.使用時(shí)需要注意舊數(shù)據(jù)覆蓋的問(wèn)題.
4讲竿、sqlite3數(shù)據(jù)庫(kù)
優(yōu)點(diǎn):當(dāng)前市面上使用較多的一種數(shù)據(jù)持久化方式; 可以存儲(chǔ)大量的數(shù)據(jù),數(shù)據(jù)不會(huì)進(jìn)行覆蓋;而且進(jìn)行大量數(shù)據(jù)存儲(chǔ) 檢索非常高效.
缺點(diǎn):基于C語(yǔ)言接口,使用起來(lái)較為麻煩;易用性不強(qiáng);還需要熟記基本的SQL語(yǔ)句;
所以,我們一般會(huì)用來(lái)存儲(chǔ)大量的數(shù)據(jù).
5泥兰、CoreData技術(shù)
優(yōu)點(diǎn):支持sqlite,xml,plist等多種數(shù)據(jù)的存儲(chǔ),對(duì)于sqlite的存儲(chǔ)相較于sqlite3來(lái)說(shuō)使用方便,提供的可視化建模和高度的抽象封裝使得代碼量也大大減少;另外一個(gè)顯著的優(yōu)點(diǎn)是可以很方便的進(jìn)行數(shù)據(jù)庫(kù)的數(shù)據(jù)遷移.另外使用者不需要在進(jìn)行數(shù)據(jù)庫(kù)的學(xué)習(xí)掌握就可以完美使用
缺點(diǎn):使用步驟和牽扯的類比較多,再加上抽象度較高使得CoreData使用較為麻煩
所以,對(duì)于大量的數(shù)據(jù)的本地存儲(chǔ)我們一般使用CoreData.另外這項(xiàng)技術(shù)是由蘋(píng)果在iOS 3.0引入,對(duì)于初學(xué)者感覺(jué)吃力,但是掌握住之后定會(huì)愛(ài)不釋手.
ios多線程中對(duì)同一資源訪問(wèn)形成資源競(jìng)爭(zhēng)的處理方式
1、@synchronized(id anObject)
會(huì)自動(dòng)對(duì)參數(shù)對(duì)象加鎖题禀,保證臨界區(qū)內(nèi)的代碼線程安全(最簡(jiǎn)單的方法)
@synchronized(self)
{
// 這段代碼對(duì)其他 @synchronized(self) 都是互斥的
// self 指向同一個(gè)對(duì)象
}
2鞋诗、NSLock
NSLock對(duì)象實(shí)現(xiàn)了NSLocking protocol,包含幾個(gè)方法:
lock迈嘹,加鎖
unlock削彬,解鎖
tryLock全庸,嘗試加鎖,如果失敗了融痛,并不會(huì)阻塞線程壶笼,只是立即返回NO
lockBeforeDate:,在指定的date之前暫時(shí)阻塞線程(如果沒(méi)有獲取鎖的話)雁刷,如果到期還沒(méi)有獲取鎖覆劈,則線程被喚醒,函數(shù)立即返回NO
NSLock *theLock = [[NSLock alloc] init];
if ([theLock lock])
{
//do something here
[theLock unlock];
}
3沛励、NSRecursiveLock责语,遞歸鎖
NSRecursiveLock,多次調(diào)用不會(huì)阻塞已獲取該鎖的線程目派。
NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];
void MyRecursiveFunction(int value)
{
[theLock lock];
if (value != 0)
<span style="font-size:14px;"> </span>{
–value;
MyRecursiveFunction(value);
}
[theLock unlock];
}
MyRecursiveFunction(5);
4坤候、NSConditionLock,條件鎖
NSConditionLock企蹭,條件鎖白筹,可以設(shè)置條件
//公共部分
id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];
//線程一,生產(chǎn)者
while(true) {
[condLock lockWhenCondition:NO_DATA];
//生產(chǎn)數(shù)據(jù)
[condLock unlockWithCondition:HAS_DATA];
}
//線程二练对,消費(fèi)者
while (true) {
[condLock lockWhenCondition:HAS_DATA];
//消費(fèi)
[condLock unlockWithCondition:NO_DATA];
}
5遍蟋、NSDistributedLock,分布鎖
NSDistributedLock螟凭,分布鎖,文件方式實(shí)現(xiàn)它呀,可以跨進(jìn)程
用tryLock方法獲取鎖螺男。
用unlock方法釋放鎖。
如果一個(gè)獲取鎖的進(jìn)程在釋放鎖之前掛了纵穿,那么鎖就一直得不到釋放了下隧,此時(shí)可以通過(guò)breakLock強(qiáng)行獲取鎖。
為什么 block 要使用 copy
block 使用 copy 是從 MRC 遺留下來(lái)的“傳統(tǒng)”,在 MRC 中,方法內(nèi)部的 block 是在棧區(qū)的,使用 copy 可以把它放到堆區(qū).在 ARC 中寫(xiě)不寫(xiě)都行:對(duì)于 block 使用 copy 還是 strong 效果是一樣的谓媒,但寫(xiě)上 copy 也無(wú)傷大雅淆院,還能時(shí)刻提醒我們:編譯器自動(dòng)對(duì) block 進(jìn)行了 copy 操作。如果不寫(xiě) copy 句惯,該類的調(diào)用者有可能會(huì)忘記或者根本不知道“編譯器會(huì)自動(dòng)對(duì) block 進(jìn)行了 copy 操作”土辩,他們有可能會(huì)在調(diào)用之前自行拷貝屬性值。這種操作多余而低效抢野。
系統(tǒng)對(duì)象的 copy 與 mutableCopy 方法
不管是集合類對(duì)象(NSArray拷淘、NSDictionary、NSSet ... 之類的對(duì)象)指孤,還是非集合類對(duì)象(NSString, NSNumber ... 之類的對(duì)象)启涯,接收到copy和mutableCopy消息時(shí)贬堵,都遵循以下準(zhǔn)則:
1、 copy 返回的是不可變對(duì)象(immutableObject)结洼;如果用copy返回值調(diào)用mutable對(duì)象的方法就會(huì)crash黎做。
2、 mutableCopy 返回的是可變對(duì)象(mutableObject)松忍。
1引几、非集合類對(duì)象的copy與mutableCopy
在非集合類對(duì)象中,對(duì)不可變對(duì)象進(jìn)行copy操作挽铁,是指針復(fù)制伟桅,mutableCopy操作是內(nèi)容復(fù)制;
對(duì)可變對(duì)象進(jìn)行copy和mutableCopy都是內(nèi)容復(fù)制
2叽掘、集合類對(duì)象的copy與mutableCopy
在集合類對(duì)象中楣铁,對(duì)不可變對(duì)象進(jìn)行copy操作,是指針復(fù)制更扁,mutableCopy操作是內(nèi)容復(fù)制盖腕;
對(duì)可變對(duì)象進(jìn)行copy和mutableCopy都是內(nèi)容復(fù)制。但是:集合對(duì)象的內(nèi)容復(fù)制僅限于對(duì)象本身浓镜,對(duì)集合內(nèi)的對(duì)象元素仍然是指針復(fù)制溃列。(即單層內(nèi)容復(fù)制)
【總結(jié)】
只有對(duì)不可變對(duì)象進(jìn)行copy操作是指針復(fù)制(淺復(fù)制),其它情況都是內(nèi)容復(fù)制(深復(fù)制)膛薛!