-
什么是ARC(ARC是為了解決什么問(wèn)題誕生的)?
- ARC是Auto Reference Counting的縮寫,即自動(dòng)引用計(jì)數(shù),由編譯器在代碼合適的位置中自動(dòng)添加retain/Release/Autorelease/dealloc方法從而進(jìn)行內(nèi)存管理.
- ARC幾個(gè)要點(diǎn):
在對(duì)象被創(chuàng)建時(shí) retain count +1,在對(duì)象被release時(shí) retain count -1.當(dāng)retain count 為0 時(shí),銷毀對(duì)象。
程序中加入autoreleasepool的對(duì)象會(huì)由系統(tǒng)自動(dòng)加上autorelease方法,如果該對(duì)象引用計(jì)數(shù)為0,則銷毀。
那么ARC是為了解決什么問(wèn)題誕生的呢?這個(gè)得追溯到MRC手動(dòng)內(nèi)存管理時(shí)代說(shuō)起。
MRC下內(nèi)存管理的缺點(diǎn):- 當(dāng)我們要釋放一個(gè)堆內(nèi)存時(shí),首先要確定指向這個(gè)堆空間的指針都被release了。(避免提前釋放)
- 釋放指針指向的堆空間,首先要確定哪些指針指向同一個(gè)堆,這些指針只能釋放一次。(MRC下即誰(shuí)創(chuàng)建,誰(shuí)釋放,避免重復(fù)釋放)
- 模塊化操作時(shí),對(duì)象可能被多個(gè)模塊創(chuàng)建和使用,不能確定最后由誰(shuí)去釋放。
- 多線程操作時(shí),不確定哪個(gè)線程最后使用完畢
-
請(qǐng)解釋一下關(guān)鍵詞的區(qū)別:
- assign && weak
- assign不會(huì)改變引用計(jì)數(shù),通常用于非指針變量的基礎(chǔ)數(shù)據(jù)類型直接賦值,weak通常用于指向同一塊內(nèi)存地址的對(duì)象.
- weak修飾的指針默認(rèn)nil。在OC中向nil對(duì)象發(fā)送消息是安全的
- __block對(duì)應(yīng)property的copy __weak對(duì)象proerty的weak
- 加了_block的局部變量才可以在block內(nèi)進(jìn)行修改
- __block修改數(shù)組或指針時(shí),block只修改指針上的內(nèi)容
- __block修改變量,內(nèi)存管理的關(guān)鍵字為copy,會(huì)引起內(nèi)存泄露。在ARC下,要避免block出現(xiàn)循環(huán)引用 weak typedof(self)weakSelf = self;
- __weak修飾變量是弱引用
- assign && weak
-
__block在ARC和非ARC下含義一樣嗎?
- 不一樣的。在MRC中的block variable在block中使用是不會(huì)retain的
但是在ARC中的block則retain的,取而代之的是用weak或者unsafe-unretained來(lái)更精確的描述weak reference的目的。
其中前者只能iOS5以后才能用,但是比較好(對(duì)象release之后,指針會(huì)直接nil),后者則是ARC環(huán)境為了兼容4.x下面的
__block MyClass *temp = ...;//MRC環(huán)境下使用 __weak MyClass *temp = ...;//ARC支持iOS5.0以上的版本 __unsafe_retained MyClass *temp = ...;//ARC且可兼容到4.x以下的版本
- 不一樣的。在MRC中的block variable在block中使用是不會(huì)retain的
-
為什么其他語(yǔ)言里叫函數(shù)調(diào)用,Object-C里則叫給我對(duì)象發(fā)消息(或者談下對(duì)runtime的理解)
- 在java中,類和方法在編譯期就綁定在一起
- 在OC中,方法調(diào)用是向類發(fā)送消息,如(bady cry)在運(yùn)行時(shí)會(huì)轉(zhuǎn)換成objc_msgSend(bady,cry),向?qū)ο蟀l(fā)送消息時(shí)根據(jù)isa指針找到類,在根據(jù)類的調(diào)度表查找方法,沒(méi)找到方法則在父類中查找直至基類,如果始終沒(méi)有找到返回nil
- Objective-C 的 Runtime 鑄就了它動(dòng)態(tài)語(yǔ)言的特性,這些深層次的知識(shí)雖然平時(shí)寫代碼用的少一些,但是卻是每個(gè) Objc 程序員需要了解的。Objc Runtime使得C具有了面向?qū)ο竽芰Γ诔绦蜻\(yùn)行時(shí)創(chuàng)建,檢查,修改類、對(duì)象和它們的方法。可以使用runtime的一系列方法實(shí)現(xiàn)。
-
什么是method swizzling?
- 在Objective-C中調(diào)用一個(gè)方法,其實(shí)是向一個(gè)對(duì)象發(fā)送消息,查找消息的唯一依據(jù)是selector的名字。利用Objective-C的動(dòng)態(tài)特性,可以實(shí)現(xiàn)在運(yùn)行時(shí)偷換selector對(duì)應(yīng)的方法實(shí)現(xiàn),達(dá)到給方法掛鉤的目的。
每個(gè)類都有一個(gè)方法列表,存放著selector的名字和方法實(shí)現(xiàn)的映射關(guān)系。IMP有點(diǎn)類似函數(shù)指針,指向具體的Method實(shí)現(xiàn)。
image1
我們可以利用 method_exchangeImplementations 來(lái)交換2個(gè)方法中的IMP,我們可以利用 class_replaceMethod 來(lái)修改類,我們可以利用 method_setImplementation 來(lái)直接設(shè)置某個(gè)方法的IMP,歸根結(jié)底,都是偷換了selector的IMP,如下圖所示:
image2
- 在Objective-C中調(diào)用一個(gè)方法,其實(shí)是向一個(gè)對(duì)象發(fā)送消息,查找消息的唯一依據(jù)是selector的名字。利用Objective-C的動(dòng)態(tài)特性,可以實(shí)現(xiàn)在運(yùn)行時(shí)偷換selector對(duì)應(yīng)的方法實(shí)現(xiàn),達(dá)到給方法掛鉤的目的。
-
UIView和CALayer是什么關(guān)系?
UIView顯示在屏幕上歸功于CALayer,通過(guò)調(diào)用drawRect方法來(lái)渲染自身的內(nèi)容,調(diào)節(jié)CALayer屬性可以調(diào)整UIView的外觀,UIView繼承自UIResponder,比起CALayer可以響應(yīng)用戶操作,Xcode6之后可以方便的通過(guò)視圖調(diào)試功能查看圖層之間的關(guān)系
UIView是iOS系統(tǒng)中界面元素的基礎(chǔ),所有的界面元素都繼承自它。它本身完全是由CoreAnimation來(lái)實(shí)現(xiàn)的(Mac下似乎不是這樣),它真正的繪圖部分,是由一個(gè)叫CALayer(Core ANimation Layer)的類來(lái)管理。UIView本身,更像是一個(gè)CALayer的管理器,訪問(wèn)它的跟繪圖和坐標(biāo)有關(guān)的屬性,如frame,bounds等,實(shí)際上內(nèi)部都是訪問(wèn)它所在CALayer的相關(guān)屬性
-
UIView有個(gè)layer屬性,可以返回它的主CALayer實(shí)例,UIView有一個(gè)layerClass方法,返回主layer所使用的 類,UIView的子類,可以通過(guò)重載這個(gè)方法,來(lái)讓UIView使用不同的CALayer來(lái)顯示,例如通過(guò)
- (class) layerClass { return ([CAEAGLLayer class]);
}
使某個(gè)UIView的子類使用GL來(lái)進(jìn)行繪制。
* UIView的CALayer類似UIView的子View樹(shù)形結(jié)構(gòu),也可以向它的layer上添加子layer,來(lái)完成某些特殊的表 示。例如下面的代碼
會(huì)在目標(biāo)View上敷上一層黑色的透明薄膜。
```
grayCover = [[CALayer alloc]init];
grayCover.backgroudColor = [[UIColor blackColor]colorWithAlphaComponent:0.2].CGColor;
[self.layer addSubLayer:grayCover];
* UIView的layer樹(shù)形在系統(tǒng)內(nèi)部,被系統(tǒng)維護(hù)著三份copy(這段理解有點(diǎn)吃不準(zhǔn))。
- 邏輯樹(shù),就是代碼里可以操縱的,例如更改layer的屬性等等就在這一份。
- 動(dòng)畫樹(shù),這是一個(gè)中間層,系統(tǒng)正在這一層上更改屬性,進(jìn)行各種渲染操作。
- 顯示樹(shù),這棵樹(shù)的內(nèi)容是當(dāng)前正被顯示在屏幕上的內(nèi)容。
這三棵樹(shù)的邏輯結(jié)構(gòu)都是一樣的,區(qū)別只有各自的屬性。
-
loadView干嘛用的?
loadView在View為nil時(shí)調(diào)用,早于ViewDidLoad,通常用于代碼實(shí)現(xiàn)控件,收到內(nèi)存警告時(shí)會(huì)再次調(diào)用。loadView默認(rèn)做的事情是:如果此VIewcontroller存在一個(gè)對(duì)應(yīng)的nib文件,那么就加載這個(gè)nib。否則,就創(chuàng)建一個(gè)UIView對(duì)象。如果你用Interface BVuilder來(lái)創(chuàng)建界面,那么不應(yīng)該重載這個(gè)方法。
-
如果你想自己創(chuàng)建View對(duì)象,那么可以重載這個(gè)方法,此時(shí)你需要自己給View屬性賦值。你自定義的方法不應(yīng)該調(diào)用super。如果你需要對(duì)View做一些其他定制操作,在ViewDidload中去做
根據(jù)上面的文檔可以知道,有兩種情況:
1、如果你用了nib文件,重載這個(gè)方法就沒(méi)有太大意義。因?yàn)閘oadView的作用就是加載nib。如果你重載了這個(gè)方法不調(diào)用super,那么nib文件就不會(huì)被加載。如果調(diào)用了super,那么view已經(jīng)加載完了,你需要做的其他事情在viewDidLoad里面做更合適。
2、如果你沒(méi)有用nib,這個(gè)方法默認(rèn)就是創(chuàng)建一個(gè)空的view對(duì)象。如果你想自己控制view對(duì)象的創(chuàng)建,例如創(chuàng)建一個(gè)特殊尺寸的view,那么可以重載這個(gè)方法,自己創(chuàng)建一個(gè)UIView對(duì)象,然后指定 self.view = myView; 但這種情況也沒(méi)有必要調(diào)用super,因?yàn)榉凑阋膊恍枰趕uper方法里面創(chuàng)建的view對(duì)象。如果調(diào)用了super,那么就是浪費(fèi)了一些資源而已
參考:http://www.cnblogs.com/dyllove98/archive/2013/06/06/3123005.html
-
GCD有哪幾種Queue?你自己建立過(guò)串行的Queue嗎?背后的線程模型是什么樣的?
- globalQueue和mainQueue
- 建立過(guò),歡迎頁(yè)完成一系列的動(dòng)畫后,彈出登錄框
- 歡迎頁(yè)動(dòng)畫并行執(zhí)行,前者和后者串行執(zhí)行
- 主隊(duì)列dispatch_main_queue();串行更新UI
- 全局隊(duì)列dispatch_global_queue();并行,四個(gè)優(yōu)先級(jí):background,low,default,high
- 自定義隊(duì)列dispatch_queue_t queue;可以自定義是并行DISPATCH_QUEUE_CONCURRENT或DISPATCH_QUEUE_SERIAL
-
用過(guò)Core Data 或者 SQLite嗎?讀寫是分線程的嗎?遇到過(guò)死鎖沒(méi)?如何解決的?
- 用過(guò)SQLite,丟給FMDatabaseQueue或者NSLock加鎖
-
HTTP協(xié)議中POST方法和GET方法有那些區(qū)別?
- GET用于向服務(wù)器請(qǐng)求數(shù)據(jù)POST用于提交數(shù)據(jù)
- GET請(qǐng)求,請(qǐng)求提以參數(shù)拼接形式暴露在地址欄,而POST請(qǐng)求則放在請(qǐng)求體里面,因此GET請(qǐng)求不適合用于驗(yàn)證密碼等操作
- 更加服務(wù)器不同,POST請(qǐng)求會(huì)有不同的長(zhǎng)度限制
-
什么是二叉搜索樹(shù)?時(shí)間復(fù)雜度是什么?
- 采用二叉樹(shù)鏈表作為存儲(chǔ)結(jié)構(gòu),每個(gè)左節(jié)點(diǎn)均小于父節(jié)點(diǎn),每個(gè)右節(jié)點(diǎn)均大于父節(jié)點(diǎn)
- O(log2(n))
-
沙盒目錄結(jié)構(gòu)是怎樣的?各自用于那些場(chǎng)景?
- Application//存放程序源文件,上架前經(jīng)過(guò)數(shù)字簽名,上架后不可修改
- Documents//常用目錄,iCloud備份目錄,存放數(shù)據(jù)
- Library
- Caches//存放體積大又不需要備份的數(shù)據(jù)
- Preference//設(shè)置目錄,iCloud會(huì)備份設(shè)置信息
- tmp//存放臨時(shí)文件
-
#define和const變量有什么區(qū)別?
- define在預(yù)處理階段進(jìn)行簡(jiǎn)單的替換,const在編譯階段使用
- 宏不做類型檢查,僅僅展開(kāi)替換,const有數(shù)據(jù)類型,會(huì)執(zhí)行類型檢查
- 宏不分配內(nèi)存,僅僅展開(kāi)替換,const會(huì)分配內(nèi)存
- define不能調(diào)試,const可以調(diào)試
- define定義的常量在替換后運(yùn)行過(guò)程中會(huì)不斷地占用內(nèi)存,而const定義的常量存儲(chǔ)在數(shù)據(jù)段,只有一份copy,效率更高
- definde可以定義一些簡(jiǎn)單的函數(shù),const不可以
-
TCP和UDP有什么區(qū)別?
- TCP是面向連接的,建立連接需要經(jīng)歷三次握手,保證數(shù)據(jù)正確性和數(shù)據(jù)順序
- UDP是非連接的協(xié)議,傳送數(shù)據(jù)受生成速度,傳輸帶寬等限制,可能造成丟包
- UDP一臺(tái)服務(wù)端可以同時(shí)向多個(gè)客戶端傳輸信息
- TCP報(bào)頭體積更大,對(duì)系統(tǒng)資源要求更多
-
如何制作一個(gè)靜態(tài)庫(kù)/動(dòng)態(tài)庫(kù)?他們的區(qū)別是什么?
- Xcode6支持制作靜態(tài)庫(kù)/動(dòng)態(tài)庫(kù) framework
- 無(wú)論是動(dòng)態(tài)庫(kù)還是靜態(tài)庫(kù)都是區(qū)分真機(jī)和模擬器的,需要lipo命令進(jìn)行合并
- 靜態(tài)庫(kù)編譯靜態(tài)庫(kù)文件裝入程序空間,動(dòng)態(tài)庫(kù)是文件動(dòng)態(tài)裝入內(nèi)存
- 動(dòng)態(tài)庫(kù)執(zhí)行到相關(guān)函數(shù)才會(huì)被調(diào)用,節(jié)省空間
-
請(qǐng)簡(jiǎn)單的介紹下APNS發(fā)送系統(tǒng)消息的機(jī)制
- 為什么需要APNS?為了杜絕安卓那種為了接受通知不停后臺(tái)喚醒保持長(zhǎng)連接的行為
- 由iOS系統(tǒng)和APNS進(jìn)行長(zhǎng)連接替代
- 應(yīng)用在通知中心就像注冊(cè),由iOS系統(tǒng)向APNS請(qǐng)求返回設(shè)備令牌
- 應(yīng)用程序接收到設(shè)備令牌并發(fā)送給服務(wù)器
- 服務(wù)器把要推送的內(nèi)容和設(shè)備發(fā)送給APNS
- APNS根據(jù)設(shè)備令牌找到設(shè)備,再由iOS根據(jù)APPID把推送內(nèi)容展示
-
請(qǐng)簡(jiǎn)述Responder Chain?
- UIResponder是UIView 和 UIViewController共同的父類,負(fù)責(zé)分發(fā)處理事件
- 在捕獲到UIEvent后從AppDelegate->UIAppcation->UIWindow->UIViewController->UIView->SubView 進(jìn)行查找
- 然后從SubView開(kāi)始嘗試響應(yīng)這個(gè)事件,并傳遞給nextResponder,如果父節(jié)點(diǎn)不能響應(yīng)則不再繼續(xù)傳遞
-
pushViewController和presentViewController有什么區(qū)別?
- 兩者都是在多個(gè)試圖控制器間跳轉(zhuǎn)的函數(shù)
- presentViewController提供的是一個(gè)模態(tài)視圖控制器
- pushViewController提供一個(gè)棧控制器數(shù)組,push/pop
-
請(qǐng)簡(jiǎn)述UITableView的復(fù)用機(jī)制
- UITableView在創(chuàng)建表視圖時(shí),不會(huì)創(chuàng)建numberOfRowsInSection那么多的cell,不然在所有APP標(biāo)配上拉加載更多條件下,iPhone內(nèi)存必然是吃不消的,通常只會(huì)創(chuàng)建當(dāng)前頁(yè)面最大可顯示Cell個(gè)數(shù)加一個(gè)(實(shí)際測(cè)試有時(shí)會(huì)加二),Cell離開(kāi)當(dāng)前屏幕后會(huì)從隊(duì)列中移除,也是基于這個(gè)原因,確定高度的Cell因?yàn)轫?yè)面要顯示的Cell個(gè)數(shù)唯一確定,所以在性能上能夠有所提高
- 復(fù)用隊(duì)列的元素增加:只有在cell被滑動(dòng)出界面的時(shí)候,此cell才會(huì)被加入到復(fù)用隊(duì)列中。每次在創(chuàng)建cell的時(shí)候,程序會(huì)首先通過(guò)調(diào)用dequeueReusableCellWithIdentifier:cellType方法,到復(fù)用隊(duì)列中去尋找標(biāo)示符為”cellType”的cell,如果找不到,返回nil,然后程序去通過(guò)調(diào)用[[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:cellType] autorelease]來(lái)創(chuàng)建標(biāo)示符為”cellType”的cell。
-
如何應(yīng)對(duì)APP版本升級(jí),數(shù)據(jù)結(jié)構(gòu)隨之變化?
- 自己解除的Sqlite相對(duì)多一些,通常的作法是重命名舊版數(shù)據(jù)庫(kù)文件->創(chuàng)建新版本表格->導(dǎo)入舊版本數(shù)據(jù)->刪除舊版本表
- 跨版本升級(jí)的問(wèn)題,數(shù)據(jù)庫(kù)更新的相關(guān)操作不做合并,依次迭代更新
- Core data接觸不多,大部分改動(dòng)都在輕量化遷移支持范圍內(nèi),復(fù)雜的需要重寫指定映射關(guān)系
-
描述一個(gè)你所遇到retain cycle例子
block中的循環(huán)引用:一個(gè)ViewController
@property (nonatomic,strong)HttpRequestHandler * handler; @property (nonatomic,strong)NSData *data; _handler = [httpRequestHandler sharedManager]; [ downloadData:^(id responseData){ _data = responseData; }];
self 擁有_handler, _handler 擁有block, block擁有self(因?yàn)槭褂昧藄elf的_data屬性,block會(huì)copy 一份self)
解決方法:__weak typedof(self)weakSelf = self [ downloadData:^(id responseData){ weakSelf.data = responseData; }];
-
+(void)load; +(void)initialize;有什么用處?
-
當(dāng)類對(duì)象被引入項(xiàng)目時(shí), runtime 會(huì)向每一個(gè)類對(duì)象發(fā)送 load 消息. load 方法還是非常的神奇的, 因?yàn)樗鼤?huì)在每一個(gè)類甚至分類被引入時(shí)僅調(diào)用一次, 調(diào)用的順序是父類優(yōu)先于子類, 子類優(yōu)先于分類. 而且 load 方法不會(huì)被類自動(dòng)繼承, 每一個(gè)類中的 load 方法都不需要像 viewDidLoad 方法一樣調(diào)用父類的方法. 由于 load 方法會(huì)在類被 import 時(shí)調(diào)用一次, 而這時(shí)往往是改變類的行為的最佳時(shí)機(jī). 我在 DKNightVersion 中使用 method swizlling 來(lái)修改原有的方法時(shí), 就是在分類 load 中實(shí)現(xiàn)的.
initialize 方法和 load 方法有一些不同, 它雖然也會(huì)在整個(gè) runtime 過(guò)程中調(diào)用一次, 但是它是在該類的第一個(gè)方法執(zhí)行之前調(diào)用, 也就是說(shuō) initialize 的調(diào)用是惰性的, 它的實(shí)現(xiàn)也與我們?cè)谄綍r(shí)使用的惰性初始化屬性時(shí)基本相同. 我在實(shí)際的項(xiàng)目中并沒(méi)有遇到過(guò)必須使用這個(gè)方法的情況, 在該方法中主要做靜態(tài)變量的設(shè)置并用于確保在實(shí)例初始化前某些條件必須滿足.
在Objective-C中,runtime會(huì)自動(dòng)調(diào)用每個(gè)類的兩個(gè)方法。+load會(huì)在類初始加載時(shí)調(diào)用,+initialize會(huì)在第一次調(diào)用類的類方法或?qū)嵗椒ㄖ氨徽{(diào)用。這兩個(gè)方法是可選的,且只有在實(shí)現(xiàn)了它們時(shí)才會(huì)被調(diào)用。
共同點(diǎn):兩個(gè)方法都只會(huì)被調(diào)用一次。
-
-
如何高性能的給 UIImageView 加個(gè)圓角? (不準(zhǔn)說(shuō) layer.cornerRadius!)
- 一般情況下給 UIImageView 或者說(shuō) UIKit 的控件添加圓角都是改變
clipsToBounds
和layer.cornerRadius
, 這樣大約兩行代碼就可以解決這個(gè)問(wèn)題. 但是, 這樣使用這樣的方法會(huì)強(qiáng)制
Core Animation 提前渲染屏幕的離屏繪制, 而離屏繪制就會(huì)為性能帶來(lái)負(fù)面影響.
我們也可以使用另一種比較復(fù)雜的方式來(lái)為圖片添加圓角, 這里就用到了貝塞爾曲線.
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
- 一般情況下給 UIImageView 或者說(shuō) UIKit 的控件添加圓角都是改變
imageView.center = CGPointMake(200, 300);
UIImage *anotherImage = [UIImage imageNamed:@"image"];
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
cornerRadius:50] addClip];
[anotherImage drawInRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self.view addSubview:imageView];
在這里使用了貝塞爾曲線"切割"個(gè)這個(gè)圖片, 給 `UIImageView` 添加了的圓角.
24. 使用drawRect有什么影響?(這個(gè)可深可淺,你至少得用過(guò)。。)
* drawRect方法依賴Core Graphics框架來(lái)進(jìn)行自定義的繪制,但這種方法主要的缺點(diǎn)就是它處理touch事件的方式:每次按鈕被點(diǎn)擊后,都會(huì)用setNeddsDisplay進(jìn)行強(qiáng)制重繪;而且不止一次,每次單點(diǎn)事件觸發(fā)兩次執(zhí)行。這樣的話從性能的角度來(lái)說(shuō),對(duì)CPU和內(nèi)存來(lái)說(shuō)都是欠佳的。特別是如果在我們的界面上有多個(gè)這樣的UIButton實(shí)例。
* 這個(gè)方法的主要作用是根據(jù)傳入的 rect 來(lái)繪制圖像 [參見(jiàn)文檔](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instm/UIView/drawRect:). 這個(gè)方法的默認(rèn)實(shí)現(xiàn)沒(méi)有做任何事情, 我們可以在這個(gè)方法中使用 Core Graphics 和 UIKit 來(lái)繪制視圖的內(nèi)容.
這個(gè)方法的調(diào)用機(jī)制也是非常特別. 當(dāng)你調(diào)用 setNeedsDisplay 方法時(shí), UIKit 將會(huì)把當(dāng)前圖層標(biāo)記為 dirty, 但還是會(huì)顯示原來(lái)的內(nèi)容, 直到下一次的視圖渲染周期, 才會(huì)為標(biāo)記為 dirty 的圖層重新建立 Core Graphics 上下文, 然后將內(nèi)存中的數(shù)據(jù)恢復(fù)出來(lái), 再使用 CGContextRef 進(jìn)行繪制.
相關(guān)參考:[UIView的layoutSubviews和drawRect方法何時(shí)調(diào)用](http://xyxdasnjss.iteye.com/blog/1827954)
25. ASIHttpRequest 或者 SDWebImage 里面給 UIImageView 加載圖片的邏輯是什么樣的?
* 我曾經(jīng)閱讀過(guò) SDWebImage 的源代碼, 就在這里對(duì)如何給 UIImageView 加載圖片做一個(gè)總結(jié)吧, SDWebImage 中為 UIView 提供了一個(gè)分類叫做 WebCache, 這個(gè)分類中有一個(gè)最常用的接口, sd_setImageWithURL:placeholderImage:, 這個(gè)分類同時(shí)提供了很多類似的方法, 這些方法最終會(huì)調(diào)用一個(gè)同時(shí)具有 option progressBlock completionBlock 的方法, 而在這個(gè)類最終被調(diào)用的方法首先會(huì)檢查是否傳入了 placeholderImage 以及對(duì)應(yīng)的參數(shù), 并設(shè)置 placeholderImage.
然后會(huì)獲取 SDWebImageManager 中的單例調(diào)用一個(gè) downloadImageWithURL:... 的方法來(lái)獲取圖片, 而這個(gè) manager 獲取圖片的過(guò)程有大體上分為兩部分, 它首先會(huì)在 SDWebImageCache 中尋找圖片是否有對(duì)應(yīng)的緩存, 它會(huì)以 url 作為數(shù)據(jù)的索引先在內(nèi)存中尋找是否有對(duì)應(yīng)的緩存, 如果緩存未命中就會(huì)在磁盤中利用 MD5 處理過(guò)的 key 來(lái)繼續(xù)查詢對(duì)應(yīng)的數(shù)據(jù), 如果找到了, 就會(huì)把磁盤中的緩存?zhèn)浞莸絻?nèi)存中.
然而, 假設(shè)我們?cè)趦?nèi)存和磁盤緩存中都沒(méi)有命中, 那么 manager 就會(huì)調(diào)用它持有的一個(gè) SDWebImageDownloader 對(duì)象的方法 downloadImageWithURL:... 來(lái)下載圖片, 這個(gè)方法會(huì)在執(zhí)行的過(guò)程中調(diào)用另一個(gè)方法 addProgressCallback:andCompletedBlock:fotURL:createCallback: 來(lái)存儲(chǔ)下載過(guò)程中和下載完成的回調(diào), 當(dāng)回調(diào)塊是第一次添加的時(shí)候, 方法會(huì)實(shí)例化一個(gè) NSMutableURLRequest 和 SDWebImageDownloaderOperation, 并將后者加入 downloader 持有的下載隊(duì)列開(kāi)始圖片的異步下載.
而在圖片下載完成之后, 就會(huì)在主線程設(shè)置 image, 完成整個(gè)圖像的異步下載和配置.
26. 使用atomic一定是線程安全的嗎?
* 不是,atomic的本意是指屬性的存取方法是線程安全的(thread safe),并不保證整個(gè)對(duì)象是線程安全的。比如,聲明一個(gè)NSMutableArray的原子屬性stuff,此時(shí)self.stuff 和self.stuff = othersulf都是線程安全的。但是,使用[self.stuff objectAtIndex:index]就不是線程安全的,需要用鎖來(lái)保證線程安全性。
----------
> 參考:
> [http://www.zhihu.com/question/19604641](http://www.zhihu.com/question/19604641)
> [http://draveness.me/guan-yu-xie-ios-wen-ti-de-jie-da/](http://draveness.me/guan-yu-xie-ios-wen-ti-de-jie-da/)
> [http://www.lxweimin.com/p/d72c4b595c7b](http://www.lxweimin.com/p/d72c4b595c7b)
> [http://weibo.com/1832164643/Ct3B4hzl3?type=comment#_rnd1438104612567](http://weibo.com/1832164643/Ct3B4hzl3?type=comment#_rnd1438104612567)