-
什么是ARC(ARC是為了解決什么問題誕生的)儡司?
- ARC是Auto Reference Counting的縮寫债蓝,即自動引用計數(shù),由編譯器在代碼合適的位置中自動添加retain/Release/Autorelease/dealloc方法從而進行內存管理.
- ARC幾個要點:
在對象被創(chuàng)建時 retain count +1,在對象被release時 retain count -1.當retain count 為0 時挺智,銷毀對象。
程序中加入autoreleasepool的對象會由系統(tǒng)自動加上autorelease方法窗宦,如果該對象引用計數(shù)為0赦颇,則銷毀。
那么ARC是為了解決什么問題誕生的呢赴涵?這個得追溯到MRC手動內存管理時代說起媒怯。
MRC下內存管理的缺點:- 當我們要釋放一個堆內存時,首先要確定指向這個堆空間的指針都被release了髓窜。(避免提前釋放)
- 釋放指針指向的堆空間扇苞,首先要確定哪些指針指向同一個堆,這些指針只能釋放一次寄纵。(MRC下即誰創(chuàng)建鳖敷,誰釋放,避免重復釋放)
- 模塊化操作時程拭,對象可能被多個模塊創(chuàng)建和使用哄陶,不能確定最后由誰去釋放。
- 多線程操作時哺壶,不確定哪個線程最后使用完畢
-
請解釋一下關鍵詞的區(qū)別:
- assign && weak
- assign不會改變引用計數(shù)屋吨,通常用于非指針變量的基礎數(shù)據(jù)類型直接賦值,weak通常用于指向同一塊內存地址的對象.
- weak修飾的指針默認nil山宾。在OC中向nil對象發(fā)送消息是安全的
- __block對應property的copy __weak對象proerty的weak
- 加了_block的局部變量才可以在block內進行修改
- __block修改數(shù)組或指針時,block只修改指針上的內容
- __block修改變量至扰,內存管理的關鍵字為copy,會引起內存泄露资锰。在ARC下敢课,要避免block出現(xiàn)循環(huán)引用 weak typedof(self)weakSelf = self;
- __weak修飾變量是弱引用
- assign && weak
-
__block在ARC和非ARC下含義一樣嗎?
- 不一樣的。在MRC中的block variable在block中使用是不會retain的
但是在ARC中的block則retain的直秆,取而代之的是用weak或者unsafe-unretained來更精確的描述weak reference的目的濒募。
其中前者只能iOS5以后才能用,但是比較好(對象release之后圾结,指針會直接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中使用是不會retain的
-
為什么其他語言里叫函數(shù)調用瑰剃,Object-C里則叫給我對象發(fā)消息(或者談下對runtime的理解)
- 在java中,類和方法在編譯期就綁定在一起
- 在OC中筝野,方法調用是向類發(fā)送消息,如(bady cry)在運行時會轉換成objc_msgSend(bady,cry),向對象發(fā)送消息時根據(jù)isa指針找到類晌姚,在根據(jù)類的調度表查找方法,沒找到方法則在父類中查找直至基類歇竟,如果始終沒有找到返回nil
- Objective-C 的 Runtime 鑄就了它動態(tài)語言的特性挥唠,這些深層次的知識雖然平時寫代碼用的少一些,但是卻是每個 Objc 程序員需要了解的焕议。Objc Runtime使得C具有了面向對象能力宝磨,在程序運行時創(chuàng)建,檢查盅安,修改類懊烤、對象和它們的方法】矶眩可以使用runtime的一系列方法實現(xiàn)腌紧。
-
什么是method swizzling?
- 在Objective-C中調用一個方法,其實是向一個對象發(fā)送消息畜隶,查找消息的唯一依據(jù)是selector的名字壁肋。利用Objective-C的動態(tài)特性,可以實現(xiàn)在運行時偷換selector對應的方法實現(xiàn)籽慢,達到給方法掛鉤的目的浸遗。
每個類都有一個方法列表,存放著selector的名字和方法實現(xiàn)的映射關系箱亿。IMP有點類似函數(shù)指針跛锌,指向具體的Method實現(xiàn)。
image1
我們可以利用 method_exchangeImplementations 來交換2個方法中的IMP届惋,我們可以利用 class_replaceMethod 來修改類髓帽,我們可以利用 method_setImplementation 來直接設置某個方法的IMP,歸根結底脑豹,都是偷換了selector的IMP郑藏,如下圖所示:
image2
- 在Objective-C中調用一個方法,其實是向一個對象發(fā)送消息畜隶,查找消息的唯一依據(jù)是selector的名字壁肋。利用Objective-C的動態(tài)特性,可以實現(xiàn)在運行時偷換selector對應的方法實現(xiàn)籽慢,達到給方法掛鉤的目的浸遗。
-
UIView和CALayer是什么關系?
UIView顯示在屏幕上歸功于CALayer,通過調用drawRect方法來渲染自身的內容瘩欺,調節(jié)CALayer屬性可以調整UIView的外觀必盖,UIView繼承自UIResponder拌牲,比起CALayer可以響應用戶操作,Xcode6之后可以方便的通過視圖調試功能查看圖層之間的關系
UIView是iOS系統(tǒng)中界面元素的基礎歌粥,所有的界面元素都繼承自它塌忽。它本身完全是由CoreAnimation來實現(xiàn)的(Mac下似乎不是這樣),它真正的繪圖部分失驶,是由一個叫CALayer(Core ANimation Layer)的類來管理土居。UIView本身,更像是一個CALayer的管理器突勇,訪問它的跟繪圖和坐標有關的屬性,如frame坷虑,bounds等甲馋,實際上內部都是訪問它所在CALayer的相關屬性
-
UIView有個layer屬性,可以返回它的主CALayer實例迄损,UIView有一個layerClass方法定躏,返回主layer所使用的 類,UIView的子類芹敌,可以通過重載這個方法痊远,來讓UIView使用不同的CALayer來顯示,例如通過
- (class) layerClass { return ([CAEAGLLayer class]);
}
使某個UIView的子類使用GL來進行繪制氏捞。
* UIView的CALayer類似UIView的子View樹形結構碧聪,也可以向它的layer上添加子layer,來完成某些特殊的表 示液茎。例如下面的代碼
會在目標View上敷上一層黑色的透明薄膜逞姿。
```
grayCover = [[CALayer alloc]init];
grayCover.backgroudColor = [[UIColor blackColor]colorWithAlphaComponent:0.2].CGColor;
[self.layer addSubLayer:grayCover];
* UIView的layer樹形在系統(tǒng)內部,被系統(tǒng)維護著三份copy(這段理解有點吃不準)捆等。
- 邏輯樹滞造,就是代碼里可以操縱的,例如更改layer的屬性等等就在這一份栋烤。
- 動畫樹谒养,這是一個中間層,系統(tǒng)正在這一層上更改屬性明郭,進行各種渲染操作买窟。
- 顯示樹,這棵樹的內容是當前正被顯示在屏幕上的內容薯定。
這三棵樹的邏輯結構都是一樣的蔑祟,區(qū)別只有各自的屬性。
-
loadView干嘛用的?
loadView在View為nil時調用沉唠,早于ViewDidLoad疆虚,通常用于代碼實現(xiàn)控件,收到內存警告時會再次調用。loadView默認做的事情是:如果此VIewcontroller存在一個對應的nib文件径簿,那么就加載這個nib罢屈。否則,就創(chuàng)建一個UIView對象篇亭。如果你用Interface BVuilder來創(chuàng)建界面缠捌,那么不應該重載這個方法。
-
如果你想自己創(chuàng)建View對象译蒂,那么可以重載這個方法曼月,此時你需要自己給View屬性賦值。你自定義的方法不應該調用super柔昼。如果你需要對View做一些其他定制操作哑芹,在ViewDidload中去做
根據(jù)上面的文檔可以知道,有兩種情況:
1捕透、如果你用了nib文件聪姿,重載這個方法就沒有太大意義。因為loadView的作用就是加載nib乙嘀。如果你重載了這個方法不調用super末购,那么nib文件就不會被加載。如果調用了super虎谢,那么view已經(jīng)加載完了盟榴,你需要做的其他事情在viewDidLoad里面做更合適。
2婴噩、如果你沒有用nib曹货,這個方法默認就是創(chuàng)建一個空的view對象。如果你想自己控制view對象的創(chuàng)建讳推,例如創(chuàng)建一個特殊尺寸的view顶籽,那么可以重載這個方法,自己創(chuàng)建一個UIView對象银觅,然后指定 self.view = myView; 但這種情況也沒有必要調用super礼饱,因為反正你也不需要在super方法里面創(chuàng)建的view對象。如果調用了super究驴,那么就是浪費了一些資源而已
參考:http://www.cnblogs.com/dyllove98/archive/2013/06/06/3123005.html
-
GCD有哪幾種Queue?你自己建立過串行的Queue嗎镊绪?背后的線程模型是什么樣的?
- globalQueue和mainQueue
- 建立過洒忧,歡迎頁完成一系列的動畫后蝴韭,彈出登錄框
- 歡迎頁動畫并行執(zhí)行,前者和后者串行執(zhí)行
- 主隊列dispatch_main_queue();串行更新UI
- 全局隊列dispatch_global_queue();并行熙侍,四個優(yōu)先級:background榄鉴,low履磨,default,high
- 自定義隊列dispatch_queue_t queue;可以自定義是并行DISPATCH_QUEUE_CONCURRENT或DISPATCH_QUEUE_SERIAL
-
用過Core Data 或者 SQLite嗎庆尘?讀寫是分線程的嗎剃诅?遇到過死鎖沒?如何解決的驶忌?
- 用過SQLite矛辕,丟給FMDatabaseQueue或者NSLock加鎖
-
HTTP協(xié)議中POST方法和GET方法有那些區(qū)別?
- GET用于向服務器請求數(shù)據(jù)POST用于提交數(shù)據(jù)
- GET請求,請求提以參數(shù)拼接形式暴露在地址欄付魔,而POST請求則放在請求體里面聊品,因此GET請求不適合用于驗證密碼等操作
- 更加服務器不同,POST請求會有不同的長度限制
-
什么是二叉搜索樹几苍?時間復雜度是什么翻屈?
- 采用二叉樹鏈表作為存儲結構,每個左節(jié)點均小于父節(jié)點擦剑,每個右節(jié)點均大于父節(jié)點
- O(log2(n))
-
沙盒目錄結構是怎樣的妖胀?各自用于那些場景芥颈?
- Application//存放程序源文件惠勒,上架前經(jīng)過數(shù)字簽名,上架后不可修改
- Documents//常用目錄爬坑,iCloud備份目錄纠屋,存放數(shù)據(jù)
- Library
- Caches//存放體積大又不需要備份的數(shù)據(jù)
- Preference//設置目錄,iCloud會備份設置信息
- tmp//存放臨時文件
-
#define和const變量有什么區(qū)別?
- define在預處理階段進行簡單的替換盾计,const在編譯階段使用
- 宏不做類型檢查售担,僅僅展開替換,const有數(shù)據(jù)類型署辉,會執(zhí)行類型檢查
- 宏不分配內存族铆,僅僅展開替換,const會分配內存
- define不能調試哭尝,const可以調試
- define定義的常量在替換后運行過程中會不斷地占用內存哥攘,而const定義的常量存儲在數(shù)據(jù)段,只有一份copy材鹦,效率更高
- definde可以定義一些簡單的函數(shù)逝淹,const不可以
-
TCP和UDP有什么區(qū)別?
- TCP是面向連接的桶唐,建立連接需要經(jīng)歷三次握手栅葡,保證數(shù)據(jù)正確性和數(shù)據(jù)順序
- UDP是非連接的協(xié)議,傳送數(shù)據(jù)受生成速度尤泽,傳輸帶寬等限制欣簇,可能造成丟包
- UDP一臺服務端可以同時向多個客戶端傳輸信息
- TCP報頭體積更大规脸,對系統(tǒng)資源要求更多
-
如何制作一個靜態(tài)庫/動態(tài)庫?他們的區(qū)別是什么?
- Xcode6支持制作靜態(tài)庫/動態(tài)庫 framework
- 無論是動態(tài)庫還是靜態(tài)庫都是區(qū)分真機和模擬器的醉蚁,需要lipo命令進行合并
- 靜態(tài)庫編譯靜態(tài)庫文件裝入程序空間燃辖,動態(tài)庫是文件動態(tài)裝入內存
- 動態(tài)庫執(zhí)行到相關函數(shù)才會被調用,節(jié)省空間
-
請簡單的介紹下APNS發(fā)送系統(tǒng)消息的機制
- 為什么需要APNS网棍?為了杜絕安卓那種為了接受通知不停后臺喚醒保持長連接的行為
- 由iOS系統(tǒng)和APNS進行長連接替代
- 應用在通知中心就像注冊黔龟,由iOS系統(tǒng)向APNS請求返回設備令牌
- 應用程序接收到設備令牌并發(fā)送給服務器
- 服務器把要推送的內容和設備發(fā)送給APNS
- APNS根據(jù)設備令牌找到設備,再由iOS根據(jù)APPID把推送內容展示
-
請簡述Responder Chain滥玷?
- UIResponder是UIView 和 UIViewController共同的父類氏身,負責分發(fā)處理事件
- 在捕獲到UIEvent后從AppDelegate->UIAppcation->UIWindow->UIViewController->UIView->SubView 進行查找
- 然后從SubView開始嘗試響應這個事件,并傳遞給nextResponder惑畴,如果父節(jié)點不能響應則不再繼續(xù)傳遞
-
pushViewController和presentViewController有什么區(qū)別蛋欣?
- 兩者都是在多個試圖控制器間跳轉的函數(shù)
- presentViewController提供的是一個模態(tài)視圖控制器
- pushViewController提供一個棧控制器數(shù)組如贷,push/pop
-
請簡述UITableView的復用機制
- UITableView在創(chuàng)建表視圖時陷虎,不會創(chuàng)建numberOfRowsInSection那么多的cell,不然在所有APP標配上拉加載更多條件下杠袱,iPhone內存必然是吃不消的尚猿,通常只會創(chuàng)建當前頁面最大可顯示Cell個數(shù)加一個(實際測試有時會加二),Cell離開當前屏幕后會從隊列中移除楣富,也是基于這個原因凿掂,確定高度的Cell因為頁面要顯示的Cell個數(shù)唯一確定,所以在性能上能夠有所提高
- 復用隊列的元素增加:只有在cell被滑動出界面的時候纹蝴,此cell才會被加入到復用隊列中庄萎。每次在創(chuàng)建cell的時候,程序會首先通過調用dequeueReusableCellWithIdentifier:cellType方法塘安,到復用隊列中去尋找標示符為”cellType”的cell糠涛,如果找不到,返回nil兼犯,然后程序去通過調用[[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:cellType] autorelease]來創(chuàng)建標示符為”cellType”的cell忍捡。
-
如何應對APP版本升級,數(shù)據(jù)結構隨之變化?
- 自己解除的Sqlite相對多一些免都,通常的作法是重命名舊版數(shù)據(jù)庫文件->創(chuàng)建新版本表格->導入舊版本數(shù)據(jù)->刪除舊版本表
- 跨版本升級的問題锉罐,數(shù)據(jù)庫更新的相關操作不做合并,依次迭代更新
- Core data接觸不多绕娘,大部分改動都在輕量化遷移支持范圍內脓规,復雜的需要重寫指定映射關系
-
描述一個你所遇到retain cycle例子
block中的循環(huán)引用:一個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(因為使用了self的_data屬性,block會copy 一份self)
解決方法:__weak typedof(self)weakSelf = self [ downloadData:^(id responseData){ weakSelf.data = responseData; }];
-
+(void)load; +(void)initialize险领;有什么用處侨舆?
-
當類對象被引入項目時, runtime 會向每一個類對象發(fā)送 load 消息. load 方法還是非常的神奇的, 因為它會在每一個類甚至分類被引入時僅調用一次, 調用的順序是父類優(yōu)先于子類, 子類優(yōu)先于分類. 而且 load 方法不會被類自動繼承, 每一個類中的 load 方法都不需要像 viewDidLoad 方法一樣調用父類的方法. 由于 load 方法會在類被 import 時調用一次, 而這時往往是改變類的行為的最佳時機. 我在 DKNightVersion 中使用 method swizlling 來修改原有的方法時, 就是在分類 load 中實現(xiàn)的.
initialize 方法和 load 方法有一些不同, 它雖然也會在整個 runtime 過程中調用一次, 但是它是在該類的第一個方法執(zhí)行之前調用, 也就是說 initialize 的調用是惰性的, 它的實現(xiàn)也與我們在平時使用的惰性初始化屬性時基本相同. 我在實際的項目中并沒有遇到過必須使用這個方法的情況, 在該方法中主要做靜態(tài)變量的設置并用于確保在實例初始化前某些條件必須滿足.
在Objective-C中秒紧,runtime會自動調用每個類的兩個方法。+load會在類初始加載時調用挨下,+initialize會在第一次調用類的類方法或實例方法之前被調用熔恢。這兩個方法是可選的,且只有在實現(xiàn)了它們時才會被調用臭笆。
共同點:兩個方法都只會被調用一次叙淌。
-
-
如何高性能的給 UIImageView 加個圓角? (不準說 layer.cornerRadius!)
- 一般情況下給 UIImageView 或者說 UIKit 的控件添加圓角都是改變
clipsToBounds
和layer.cornerRadius
, 這樣大約兩行代碼就可以解決這個問題. 但是, 這樣使用這樣的方法會強制
Core Animation 提前渲染屏幕的離屏繪制, 而離屏繪制就會為性能帶來負面影響.
我們也可以使用另一種比較復雜的方式來為圖片添加圓角, 這里就用到了貝塞爾曲線.
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
- 一般情況下給 UIImageView 或者說 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];
在這里使用了貝塞爾曲線"切割"個這個圖片, 給 `UIImageView` 添加了的圓角.
24. 使用drawRect有什么影響?(這個可深可淺愁铺,你至少得用過鹰霍。。)
* drawRect方法依賴Core Graphics框架來進行自定義的繪制茵乱,但這種方法主要的缺點就是它處理touch事件的方式:每次按鈕被點擊后茂洒,都會用setNeddsDisplay進行強制重繪;而且不止一次瓶竭,每次單點事件觸發(fā)兩次執(zhí)行督勺。這樣的話從性能的角度來說,對CPU和內存來說都是欠佳的斤贰。特別是如果在我們的界面上有多個這樣的UIButton實例智哀。
* 這個方法的主要作用是根據(jù)傳入的 rect 來繪制圖像 [參見文檔](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instm/UIView/drawRect:). 這個方法的默認實現(xiàn)沒有做任何事情, 我們可以在這個方法中使用 Core Graphics 和 UIKit 來繪制視圖的內容.
這個方法的調用機制也是非常特別. 當你調用 setNeedsDisplay 方法時, UIKit 將會把當前圖層標記為 dirty, 但還是會顯示原來的內容, 直到下一次的視圖渲染周期, 才會為標記為 dirty 的圖層重新建立 Core Graphics 上下文, 然后將內存中的數(shù)據(jù)恢復出來, 再使用 CGContextRef 進行繪制.
相關參考:[UIView的layoutSubviews和drawRect方法何時調用](http://xyxdasnjss.iteye.com/blog/1827954)
25. ASIHttpRequest 或者 SDWebImage 里面給 UIImageView 加載圖片的邏輯是什么樣的?
* 我曾經(jīng)閱讀過 SDWebImage 的源代碼, 就在這里對如何給 UIImageView 加載圖片做一個總結吧, SDWebImage 中為 UIView 提供了一個分類叫做 WebCache, 這個分類中有一個最常用的接口, sd_setImageWithURL:placeholderImage:, 這個分類同時提供了很多類似的方法, 這些方法最終會調用一個同時具有 option progressBlock completionBlock 的方法, 而在這個類最終被調用的方法首先會檢查是否傳入了 placeholderImage 以及對應的參數(shù), 并設置 placeholderImage.
然后會獲取 SDWebImageManager 中的單例調用一個 downloadImageWithURL:... 的方法來獲取圖片, 而這個 manager 獲取圖片的過程有大體上分為兩部分, 它首先會在 SDWebImageCache 中尋找圖片是否有對應的緩存, 它會以 url 作為數(shù)據(jù)的索引先在內存中尋找是否有對應的緩存, 如果緩存未命中就會在磁盤中利用 MD5 處理過的 key 來繼續(xù)查詢對應的數(shù)據(jù), 如果找到了, 就會把磁盤中的緩存?zhèn)浞莸絻却嬷?
然而, 假設我們在內存和磁盤緩存中都沒有命中, 那么 manager 就會調用它持有的一個 SDWebImageDownloader 對象的方法 downloadImageWithURL:... 來下載圖片, 這個方法會在執(zhí)行的過程中調用另一個方法 addProgressCallback:andCompletedBlock:fotURL:createCallback: 來存儲下載過程中和下載完成的回調, 當回調塊是第一次添加的時候, 方法會實例化一個 NSMutableURLRequest 和 SDWebImageDownloaderOperation, 并將后者加入 downloader 持有的下載隊列開始圖片的異步下載.
而在圖片下載完成之后, 就會在主線程設置 image, 完成整個圖像的異步下載和配置.
26. 使用atomic一定是線程安全的嗎?
* 不是腋舌,atomic的本意是指屬性的存取方法是線程安全的(thread safe)盏触,并不保證整個對象是線程安全的渗蟹。比如块饺,聲明一個NSMutableArray的原子屬性stuff,此時self.stuff 和self.stuff = othersulf都是線程安全的雌芽。但是授艰,使用[self.stuff objectAtIndex:index]就不是線程安全的,需要用鎖來保證線程安全性世落。
----------
> 參考:
> [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.reibang.com/p/d72c4b595c7b](http://www.reibang.com/p/d72c4b595c7b)
> [http://weibo.com/1832164643/Ct3B4hzl3?type=comment#_rnd1438104612567](http://weibo.com/1832164643/Ct3B4hzl3?type=comment#_rnd1438104612567)