1.簡述KVC和KVO丐巫,其中KVO實現(xiàn)原理鳄抒?
KVC : 鍵值編碼(Key-Value Coding),它是一種通過key值訪問類屬性的機制文判,而不是通過setter/getter方法訪問。其中 KVC 原理:當(dāng)調(diào)用- (void)setValue:(id)value forUndefinedKey:(NSString *)key時培遵,KVC底層的執(zhí)行機制如下:
首先搜索對應(yīng)屬性的setter方法
如果沒有找到屬性的setter方法浪藻,則會檢查+ (BOOL)accessInstanceVariablesDirectly方法是否返回了YES(該方法默認返回YES),如果返回了YES, 則KVC機制會搜索類中是否存在該屬性的成員變量捐迫,也就是_屬性名,存在則對該成員變量賦值爱葵。搜索成員變量名的順序是 _key施戴,_isKey,key萌丈,isKey赞哗。
另外我們也可以通過重寫+ (BOOL)accessInstanceVariablesDirectly方法返回NO,這個時候KVC機制就會調(diào)用 - (void)setValue:(id)value forUndefinedKey:(NSString *)key。
如果沒有找到成員變量辆雾,調(diào)用 - (void)setValue:(id)value forUndefinedKey:(NSString *)key肪笋。
2.Block實現(xiàn)原理;堆上和棧上的數(shù)據(jù)如何同步度迂?
block本質(zhì)上也是一個oc對象藤乙,他內(nèi)部也有一個isa指針。block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對象惭墓。結(jié)構(gòu)體坛梁,在棧上的情況, Block中的指針只是指向棧上的__block變量, 而當(dāng)Block/__block變量被copy到堆上以后, 堆上Block會持有堆上__block變量. 而堆上的Block再次被調(diào)用copy時, 只是Block的引用計數(shù)+1而已, 而__block變量如果被多個堆上Block持有也只涉及到引用記數(shù)的變化. 一旦Block/__block變量的引用計數(shù)為0, 就會自動從堆上釋放內(nèi)存.這里Block/__block變量在堆上的內(nèi)存管理與Objective-C對象完全一致.
3.推送如何實現(xiàn)的?
1.由App向iOS設(shè)備發(fā)送一個注冊通知腊凶,用戶需要同意系統(tǒng)發(fā)送推送罚勾。
2.iOS應(yīng)用向APNS遠程推送服務(wù)器發(fā)送App的Bundle Id和設(shè)備的UDID。
3.APNS根據(jù)設(shè)備的UDID和App的Bundle Id生成deviceToken再發(fā)回給App吭狡。
4.App再將deviceToken發(fā)送給遠程推送服務(wù)器(自己的服務(wù)器), 由服務(wù)器保存在數(shù)據(jù)庫中。
5.當(dāng)自己的服務(wù)器想發(fā)送推送時, 在遠程推送服務(wù)器中輸入要發(fā)送的消息并選擇發(fā)給哪些用戶的deviceToken丈莺,由遠程推送服務(wù)器發(fā)送給APNS划煮。
6.APNS根據(jù)deviceToken發(fā)送給對應(yīng)的用戶。
4.簡述weak的實現(xiàn)原理缔俄;
weak 關(guān)鍵字的作用弱引用弛秋,所引用對象的計數(shù)器不會加一器躏,并在引用對象被釋放的時候自動被設(shè)置為 nil;
weak是有Runtime維護的weak表;3.weak釋放為nil過程
weak被釋放為nil,需要對對象整個釋放過程了解蟹略,如下是對象釋放的整體流程:
1登失、調(diào)用objc_release
2、因為對象的引用計數(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钓猬。
對象準備釋放時,調(diào)用clearDeallocating函數(shù)撩独。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組敞曹,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個entry從weak表中刪除综膀,最后清理對象的記錄澳迫。
其實Weak表是一個hash(哈希)表,然后里面的key是指向?qū)ο蟮牡刂飞耄琕alue是Weak指針的地址的數(shù)組
總結(jié)
weak是Runtime維護了一個hash(哈希)表纲刀,用于存儲指向某個對象的所有weak指針。weak表其實是一個hash(哈希)表担平,Key是所指對象的地址示绊,Value是weak指針的地址(這個地址的值是所指對象指針的地址)數(shù)組。
5. TCP 和 UDP 的區(qū)別
TCP 為傳輸控制層協(xié)議暂论。這種協(xié)議提供面向連接的面褐、可靠的、點到點的通信取胎;
UDP 為用戶數(shù)據(jù)報協(xié)議展哭。這種協(xié)議提供非連接的、不可靠的闻蛀、點到多的通信但是比 TCP 快匪傍。
6. TCP 的三次握手
第一次握手:客戶端發(fā)送 syn 包(syn=j)到服務(wù)器,并進入 SYN_SEND 狀態(tài) 觉痛,等待服務(wù)器確認役衡;
第二次握手:服務(wù)器收到 syn 包,必須確認客戶的 SYN(ack=j+1)薪棒,同時自己也發(fā)送一個 syn 包(syn=k)手蝎,即 SYN+ACK 包榕莺,此時服務(wù)器進入 SYN+RECV 狀態(tài);
第三次握手:客戶端收到服務(wù)器的 SYN+ACK 包棵介,向服務(wù)器發(fā)送確認包 ACK(ack=k+1)钉鸯,此時發(fā)送完畢,客戶端和服務(wù)端進入 ESTABLISHED 狀態(tài)邮辽,完成三次握手
7. 屬性readwrite唠雕,readonly,assign逆巍,retain及塘,copy,nonatomic 各是什么作用锐极,在那種情況下用
(1) readwrite 是可讀可寫特性;需要生成getter方法和setter方法時
(2) readonly 是只讀特性 只會生成getter方法 不會生成setter方法 ;不希望屬性在類外改變
(3) assign 是賦值特性笙僚,setter方法將傳入?yún)?shù)賦值給實例變量;僅設(shè)置變量時;
(4) retain 表示持有特性,setter方法將傳入?yún)?shù)先保留灵再,再賦值肋层,傳入?yún)?shù)的retaincount會+1;
(5) copy 表示賦值特性,setter方法將傳入對象復(fù)制一份;需要完全一份新的變量時翎迁。
(6) nonatomic 非原子操作栋猖,決定編譯器生成的setter getter是否是原子操作,atomic表示多線程安全汪榔,一般使用nonatomic
8. @property 的本質(zhì)是什么蒲拉,ivar、getter痴腌、setter 是如何生成并添加到這個類中的
在普通 OC 對象中雌团,@property 就是編譯器自動幫我們生成一個成員變量(ivar)和它的 setter 和 getter 方法,它大概生成了五個東西:
1. objc_ivar_$類名$屬性名稱 該屬性的偏移量
2. setter 與 getter 方法對應(yīng)的實現(xiàn)函數(shù)
3. ivar_list 成員變量列表
4. method_list 方法列表
5. prop_list 屬性列表
也就是說我們每次增加一個屬性士聪,系統(tǒng)就會在成員變量列表中添加一個成員變量的描述锦援,在方法列表中添加 setter 與 getter 方法的描述,在屬性列表中增加一個屬性描述剥悟,然后計算該屬性在對象中的偏移量灵寺,然后生成 setter 與 getter 方法對應(yīng)的實現(xiàn),在 setter 方法中從偏移量開始復(fù)制区岗,在 getter 中從偏移量開始取值略板,為了能夠讀取正確的自己數(shù),系統(tǒng)對對象偏移量的指針類型進行了類型強轉(zhuǎn)慈缔。
9. @synthesize 和 @dynamic 分別有什么作用
@property 有兩個對應(yīng)的詞蚯根,一個是 @synthesize,一個是 @dynamic。如果 @synthesize 和 @dynamic 都沒寫颅拦,那么默認的就是 @syntheszie var = _var;
@synthesize 的語義是如果你沒有手動實現(xiàn) setter 方法和 getter 方法,那么編譯器會自動為你加上這兩個方法教藻。
@dynamic 告訴編譯器,屬性的 setter 與 getter 方法由用戶自己實現(xiàn)距帅,不自動生成。(當(dāng)然對于 readonly 的屬性只需提供 getter 即可)括堤。假如一個屬性被聲明為 @dynamic var碌秸,然后你沒有提供 @setter 方法和 @getter 方法,編譯的時候沒問題悄窃,但是當(dāng)程序運行到 instance.var =someVar讥电,由于缺 setter 方法會導(dǎo)致程序崩潰;或者當(dāng)運行到 someVar = var時轧抗,由于缺 getter 方法同樣會導(dǎo)致崩潰恩敌。編譯時沒問題,運行時才執(zhí)行相應(yīng)的方法横媚,這就是所謂的動態(tài)綁定纠炮。
10. get 與 post 的區(qū)別
get 是向服務(wù)器索取數(shù)據(jù)的一種請求,post 是向服務(wù)器提交數(shù)據(jù)的一種請求灯蝴;
get 沒有請求體恢口,post 有請求體;
get 使用 url 或 cookie 傳參穷躁,而 post 將數(shù)據(jù)放在 body 中耕肩;
get 請求的數(shù)據(jù)會暴露在地址欄中,而 post 不會问潭,所以 post 比 get 更安全猿诸;
get 請求對 url 長度有限制,而 post 請求對 url 理論上沒有限制睦授,但實際上两芳,各個服務(wù)器會規(guī)定對 post 提交數(shù)據(jù)大小進行限制。
11. 描述下 SDWebImage 里面給 UIImageView 加載圖片的邏輯
SDWebImage 中為 UIImageView 提供了一個分類 UIImageView+WebCache.h去枷。這個分類中有一個最常用的方法:sd_setImageWithURL:placeholderImage: 會在真實圖片出來前先顯示占位圖片怖辆,當(dāng)真實圖片被加載出來后再替換占位圖片。
加載過程大致如下:
首先會在 SDWebImageCache 中尋找圖片是否有對應(yīng)的緩存删顶,它會以 url 作為數(shù)據(jù)索引先在內(nèi)存中尋找是否有對應(yīng)的緩存竖螃,如果緩存未找到就會利用通過 MD5 處理過的 key 來繼續(xù)在磁盤中查詢對應(yīng)的數(shù)據(jù),如果找到了逗余,就會把磁盤中的數(shù)據(jù)加載到內(nèi)存中特咆,并將圖片顯示出來,如果在內(nèi)存中和磁盤緩存中都沒有找到,就會向遠程服務(wù)器發(fā)送請求腻格,開始下載圖片画拾,下載后的圖片會加載到緩存中,并寫入磁盤中菜职。整個獲取圖片的過程都是在子線程中執(zhí)行青抛,獲取到圖片后回到主線程將圖片顯示出來。
原理:
從內(nèi)存中找到圖片酬核,找到直接使用蜜另;
從沙盒中找,找到使用嫡意,緩存到內(nèi)存中举瑰;
從網(wǎng)絡(luò)上獲取,使用蔬螟,緩存到內(nèi)存此迅,緩存到沙盒。