面試的坑,不同的基礎(chǔ)就會有不同的坑,不多說了直接上面試題:(面試題與答案會持續(xù)更新)
1、簡述關(guān)鍵字assign、weak、strong、retain、copy、readonly、readwrite、nonatomic、atomic的作用?
答:assign用于基本數(shù)據(jù)類型,如:NSInteger、double、bool等。weak、retain、strong和copy都用于對象。
weak表示的是弱引用,是ARC引入的對象變量的屬性,相當(dāng)于assign,只是當(dāng)指向的對象被釋放的時候會把當(dāng)前的指針指向nil。
retain、strong、copy都表示持有該對象,strong的功能等同于retain,copy則表示會復(fù)制并指向新的對象。
readonly、readwrite是屬性讀寫權(quán)限,readonly系統(tǒng)只允許使用屬性的getter方法,readwrite則既可以訪問setter方法也可以訪問getter方法。
atomic、nonatomic是原子和非原子性訪問屬性。在多線程中訪問屬性時,atomic能保證屬性的存取安全,nonatomic則不會。
2、weak 和 assign 的區(qū)別?
答:weak功能相當(dāng)于assign都表示弱引用。但是使用weak關(guān)鍵字時,當(dāng)指向的對象被釋放的時候會把當(dāng)前的指針指向nil。assign則不會,它會造成野指針的問題。
3、weak 的實現(xiàn)原理?
答:Runtime維護(hù)了一個weak表,用于存儲指向某個對象的所有weak指針。weak表其實是一個hash表,Key是所指對象的地址,Value是weak指針的地址數(shù)組。a. 初始化時:runtime會調(diào)用objc_initWeak函數(shù),初始化一個新的weak指針指向?qū)ο蟮牡刂贰. 添加引用時:objc_initWeak函數(shù)會調(diào)用 objc_storeWeak() 函數(shù),objc_storeWeak() 的作用是更新指針指向,創(chuàng)建對應(yīng)的弱引用列表。c. 釋放時:調(diào)用 clearDeallocating 函數(shù)。clearDeallocating 函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后移除這個弱引用的散列表。
4、atomic是不是一定就是線程安全?為什么?如何保證其線程安全?
第一問答:不是完全的線程安全,只是屬性的存取方法是線程安全的。
第二問答:atomic在屬性的setter和getter方法中加入了自旋鎖,但這個鎖只能保證setter/getter存取的安全,不能保證數(shù)據(jù)結(jié)果的正確性;舉個例子:線程A、B都調(diào)用了屬性的setter方法,線程C調(diào)用屬性的getter方法,每個線程都保證了各自數(shù)據(jù)的完整性,那么D線程最后getter到的屬性值就不確定了。
第三問答:需要加入互斥鎖來解決線程安全。
5、Classroom這個類有什么問題?
@interface Classroom : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, copy) NSMutableArray *students;
@end
答:可變數(shù)組使用了copy屬性修飾,一旦通過set方法設(shè)置了該屬性值后,就不能直接使用這個屬性來調(diào)用NSMutableArray的方法了,否則會造成崩潰。
6、圖示MVC、MVVM?
7、簡述MVVM模式中VM的作用?
答:VM主要是關(guān)聯(lián)Model和View,VM負(fù)責(zé)把Model的數(shù)據(jù)同步到View顯示出來,還負(fù)責(zé)把View的修改同步回Model中。VM旨在剝離原本在MVC模式Controller中的數(shù)據(jù)解析和視圖展示邏輯。
8、簡述事件傳遞和響應(yīng)鏈?
答:事件傳遞:當(dāng)用戶觸摸屏幕時,就會生成一個事件,這個事件會被加入到UIApplication管理的事件隊列里,接下來開始自UIApplication往下傳遞,首先會傳遞給Window,然后按照View的層級結(jié)構(gòu)一層層往下傳遞,一直找到最合適的view來處理這個事件。查找最合適的View是一個遞歸過程,其中主要涉及到:hitTest:withEvent: 和 pointInside:withEvents: 這兩個方法。事件響應(yīng):當(dāng)找到最合適處理該事件的View時,會調(diào)用View的touchs方法對事件進(jìn)行響應(yīng),如果沒有重寫touchs方法的話,touchs默認(rèn)會把事件沿著響應(yīng)者鏈往上傳遞,一直到UIApplication,如果依舊不能處理事件,則這個事件將會被丟棄不做響應(yīng)。響應(yīng)者鏈?zhǔn)怯梢幌盗欣^承自UIResponder的對象組成的,它決定了響應(yīng)者對象響應(yīng)事件的先后順序。
9、如何將一個控件的觸摸事件傳遞給另一個控件處理?
答:重寫hitTest方法,返回處理事件的View;攔截touch方法,防止觸摸事件繼續(xù)傳遞。
10、開發(fā)中Runtime一般用來干啥?
答:動態(tài)添加類、添加方法、關(guān)聯(lián)屬性等。
11、替換系統(tǒng)的方法一般需要做什么處理?
答:使用dispatch_once來確保替換方法只執(zhí)行一次;替換時最好先為該類添加新方法,通過返回的Bool值來繼續(xù)替換方法操作;替換完成后需要在新方法中調(diào)用一次替換后的方法。
12、為什么說OC是一門動態(tài)語言?
答:簡單來說,就是把一些工作從編譯時推遲到運(yùn)行時;比如代碼運(yùn)行時,才能知道對象是什么類型,以及它能響應(yīng)哪些方法。主要表現(xiàn)在:動態(tài)類型、動態(tài)綁定、動態(tài)加載,三個方面。
13、什么時候會報unrecognized selector的異常?
答:向?qū)ο蟀l(fā)送一條消息時,如果經(jīng)歷消息發(fā)送、動態(tài)方法解析、消息轉(zhuǎn)發(fā),都沒有得到響應(yīng)的話,就會報這個異常。
14、消息轉(zhuǎn)發(fā)的步驟?
答:三個步驟,resInstanceMethod、forwardingTargetForSel、forwardInvocation
15、如何在子線程開啟一個runloop?
答:在子線程中調(diào)用[[NSRunLoop currentRunLoop] run];即可。
16、如何對tableView進(jìn)行性能優(yōu)化?
答:數(shù)據(jù)結(jié)構(gòu)上,計算數(shù)據(jù)占用高度等,可放在請求到數(shù)據(jù)時進(jìn)行計算。如果視圖過于復(fù)雜的話,使用異步繪制。來保證幀率在60左右 。
17、如何監(jiān)測APP的性能?
答:使用Xcode自帶Profile中的一些工具進(jìn)行查看,比如說使用Time方法調(diào)用所占時間,用Leaks查看內(nèi)存相關(guān)問題等。
18、如何縮小 ipa 包?
答:1. 資源文件優(yōu)化(無損壓縮<圖片、音頻、視頻>,刪除無用資源)。2. 可執(zhí)行文件優(yōu)化(刪除無用代碼,刪除靜態(tài)庫中的無用架構(gòu),關(guān)閉編譯器中的異常調(diào)試處理)
19、如何在不用工具也不用第三方框架的情況下,對項目進(jìn)行一個內(nèi)存泄露的監(jiān)測?
答:1. 靜態(tài)方法檢測,使用Xcode自帶的Analyze工具;2. 使用動態(tài)方法檢測,instructment工具實時檢測;3. 自己寫代碼檢測。
20、如何自定義一個tableView?
答:主要使用重用機(jī)制
21、現(xiàn)需要對5個ip,每個ip ping5次然后計算平均值,如何設(shè)計?
答:通過GCD開啟5個線程執(zhí)行 ip ping 操作,然后通過 GCD 的調(diào)度組,進(jìn)行處理平均值的計算。
22、GCD、NSOperationQueue的異同?
答:GCD和NSOperation都是多線程開發(fā),NSOperation是對GCD的封裝,底層是GCD實現(xiàn)的。
- GCD的核心是C語言實現(xiàn)的,執(zhí)行和操作簡單高效;NSOperation是對GCD的封裝的,NSOperation會多一些開銷。
- NSOperation可以設(shè)置依賴關(guān)系,GCD無法直接設(shè)置依賴關(guān)系,可以通過調(diào)度組、或柵欄函數(shù)來實現(xiàn)。
- NSOperation可以使用KVO觀察當(dāng)前狀態(tài),GCD是無法使用KVO觀察的。
- NSOperation可以設(shè)置自身的優(yōu)先級,GCD只能設(shè)置隊列優(yōu)先級。
- NSOperation是個抽象類,使用時需要繼承子類再使用;GCD執(zhí)行任務(wù)可自由組裝,自由度較強(qiáng)。
23、main函數(shù)執(zhí)行前都有什么操作?
答:1. 動態(tài)鏈接庫;2. ImageLoader加載可執(zhí)行文件<編譯過的符號表、代碼等>;3. Runtime與+load方法調(diào)用
24、+load 和 +initialize 的聯(lián)系和區(qū)別?
答:1. +load 和 +initialize 都由系統(tǒng)調(diào)用,都不需要調(diào)用super方法。2. +load 和 +initialize 都先調(diào)用類中的,再調(diào)用類別中的。3. +load 方法是在main函數(shù)之前調(diào)用的,+initialize是第一次初始化這個類之前被調(diào)用的。4. 如果子類沒有 +initialize 方法也會調(diào)用父類的方法,而 +load 方法則不會調(diào)用父類的方法。5. +load 和 +initialize 方法內(nèi)部使用了鎖,實現(xiàn)時要盡可能保持簡單,避免阻塞線程,不要再使用鎖。
25、看如下代碼打印有什么區(qū)別?
- (void)test {
NSLog(@"%@", [super class]);
NSLog(@"%@", [self class]);
}
答:打印的結(jié)果都是一樣的,因為super只是編譯器表示符,他的代表的結(jié)構(gòu)體是struct objc_super
,這個結(jié)構(gòu)體中含有receiver
、super_class
兩個數(shù)據(jù),當(dāng)使用super去發(fā)送消息時,只是優(yōu)先從父類開始找方法;而使用self發(fā)送消息時,優(yōu)先從本類開始找。本題中兩個打印代碼,消息發(fā)送者其實都是self,只是優(yōu)先找方法的位置不一樣而已!
注意:還可以延伸下,使用super、self分別去調(diào)用class、superclass消息的結(jié)果!!!