iOS高級(jí)面試題-網(wǎng)易

1、什么是arc?(arc是為了解決什么問(wèn)題誕生的?)
首先解釋ARC: automatic reference counting自動(dòng)引用計(jì)數(shù)。
ARC幾個(gè)要點(diǎn):
在對(duì)象被創(chuàng)建時(shí) retain count +1,在對(duì)象被release時(shí) retain count -1.當(dāng)retain count 為0 時(shí),銷(xiāo)毀對(duì)象。
程序中加入autoreleasepool的對(duì)象會(huì)由系統(tǒng)自動(dòng)加上autorelease方法,如果該對(duì)象引用計(jì)數(shù)為0,則銷(xiāo)毀。
那么ARC是為了解決什么問(wèn)題誕生的呢?這個(gè)得追溯到MRC手動(dòng)內(nèi)存管理時(shí)代說(shuō)起。
MRC下內(nèi)存管理的缺點(diǎn):
1.當(dāng)我們要釋放一個(gè)堆內(nèi)存時(shí),首先要確定指向這個(gè)堆空間的指針都被release了。(避免提前釋放)
2.釋放指針指向的堆空間,首先要確定哪些指針指向同一個(gè)堆,這些指針只能釋放一次。(MRC下即誰(shuí)創(chuàng)建,誰(shuí)釋放,避免重復(fù)釋放)
3.模塊化操作時(shí),對(duì)象可能被多個(gè)模塊創(chuàng)建和使用,不能確定最后由誰(shuí)去釋放。
4.多線(xiàn)程操作時(shí),不確定哪個(gè)線(xiàn)程最后使用完畢

2、請(qǐng)解釋以下keywords的區(qū)別: assign vs weak, __block vs __weak

assign適用于基本數(shù)據(jù)類(lèi)型,weak是適用于NSObject對(duì)象,并且是一個(gè)弱引用。

assign其實(shí)也可以用來(lái)修飾對(duì)象,那么我們?yōu)槭裁床挥盟??因?yàn)楸籥ssign修飾的對(duì)象在釋放之后,指針的地址還是存在的,也就是說(shuō)指針并沒(méi)有被置為nil。如果在后續(xù)的內(nèi)存分配中,剛好分到了這塊地址,程序就會(huì)崩潰掉。
而weak修飾的對(duì)象在釋放之后,指針地址會(huì)被置為nil。所以現(xiàn)在一般弱引用就是用weak。
首先__block是用來(lái)修飾一個(gè)變量,這個(gè)變量就可以在block中被修改(參考block實(shí)現(xiàn)原理)
__block:使用__block修飾的變量在block代碼快中會(huì)被retain(ARC下,MRC下不會(huì)retain)
__weak:使用__weak修飾的變量不會(huì)在block代碼塊中被retain
同時(shí),在A(yíng)RC下,要避免block出現(xiàn)循環(huán)引用 __weak typedof(self)weakSelf = self;

3、__block在arc和非arc下含義一樣嗎?
是不一樣的!!!
在MRC中__block variable在block中使用是不會(huì)retain的
但是ARC中__block則是會(huì)retain的。
取而代之的是用__weak或是__unsafe_unretained來(lái)更精確的描述weak reference的目的
其中前者只能在iOS5之后可以使用,但是比較好 (該物件release之后,此pointer會(huì)自動(dòng)置成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以后的版本

4、使用nonatomic一定是線(xiàn)程安全的嗎?
不是的。

  • atomic原子操作,系統(tǒng)會(huì)為setter方法加鎖。 具體使用 @synchronized(self){//code }
  • nonatomic不會(huì)為setter方法加鎖。
  • atomic:線(xiàn)程安全,需要消耗大量系統(tǒng)資源來(lái)為屬性加鎖
  • nonatomic:非線(xiàn)程安全,適合內(nèi)存較小的移動(dòng)設(shè)備

5、+(void)load; +(void)initialize;有什么用處?
在Objective-C中,runtime會(huì)自動(dòng)調(diào)用每個(gè)類(lèi)的兩個(gè)方法。+load會(huì)在類(lèi)初始加載時(shí)調(diào)用,+initialize會(huì)在第一次調(diào)用類(lèi)的類(lèi)方法或?qū)嵗椒ㄖ氨徽{(diào)用。這兩個(gè)方法是可選的,且只有在實(shí)現(xiàn)了它們時(shí)才會(huì)被調(diào)用。
共同點(diǎn):兩個(gè)方法都只會(huì)被調(diào)用一次。

6、為什么其他語(yǔ)言里叫函數(shù)調(diào)用, objective c里則是給對(duì)象發(fā)消息(或者談下對(duì)runtime的理解)
先來(lái)看看怎么理解發(fā)送消息的含義:

曾經(jīng)覺(jué)得Objc特別方便上手,面對(duì)著 Cocoa 中大量 API,只知道簡(jiǎn)單的查文檔和調(diào)用。還記得初學(xué) Objective-c 時(shí)把[receiver message]當(dāng)成簡(jiǎn)單的方法調(diào)用,而無(wú)視了“發(fā)送消息”這句話(huà)的深刻含義。于是[receiver message]會(huì)被編譯器轉(zhuǎn)化為:
objc_msgSend(receiver, selector)
如果消息含有參數(shù),則為:
objc_msgSend(receiver, selector, arg1, arg2, ...)

如果消息的接收者能夠找到對(duì)應(yīng)的selector,那么就相當(dāng)于直接執(zhí)行了接收者這個(gè)對(duì)象的特定方法;否則,消息要么被轉(zhuǎn)發(fā),或是臨時(shí)向接收者動(dòng)態(tài)添加這個(gè)selector對(duì)應(yīng)的實(shí)現(xiàn)內(nèi)容,要么就干脆玩完崩潰掉。

現(xiàn)在可以看出[receiver message]真的不是一個(gè)簡(jiǎn)簡(jiǎn)單單的方法調(diào)用。因?yàn)檫@只是在編譯階段確定了要向接收者發(fā)送message這條消息,而receive將要如何響應(yīng)這條消息,那就要看運(yùn)行時(shí)發(fā)生的情況來(lái)決定了。

Objective-C 的 Runtime 鑄就了它動(dòng)態(tài)語(yǔ)言的特性,這些深層次的知識(shí)雖然平時(shí)寫(xiě)代碼用的少一些,但是卻是每個(gè) Objc 程序員需要了解的。

Objc Runtime使得C具有了面向?qū)ο竽芰?,在程序運(yùn)行時(shí)創(chuàng)建,檢查,修改類(lèi)、對(duì)象和它們的方法。可以使用runtime的一系列方法實(shí)現(xiàn)。

順便附上OC中一個(gè)類(lèi)的數(shù)據(jù)結(jié)構(gòu) /usr/include/objc/runtime.h

struct objc_class { 
Class isa OBJC_ISA_AVAILABILITY; 
//isa指針指向Meta Class,因?yàn)镺bjc的類(lèi)的本身也是一個(gè)Object,
//為了處理這個(gè)關(guān)系,runtime就創(chuàng)造了Meta Class,
//當(dāng)給類(lèi)發(fā)送[NSObject alloc]這樣消息時(shí),
//實(shí)際上是把這個(gè)消息發(fā)給了Class Object
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父類(lèi)
const char *name OBJC2_UNAVAILABLE; // 類(lèi)名
long version OBJC2_UNAVAILABLE; // 類(lèi)的版本信息,默認(rèn)為0
long info OBJC2_UNAVAILABLE; // 類(lèi)信息,供運(yùn)行期使用的一些位標(biāo)識(shí)
long instance_size OBJC2_UNAVAILABLE; // 該類(lèi)的實(shí)例變量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 該類(lèi)的成員變量鏈表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定義的鏈表
struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法緩存,對(duì)象接到一個(gè)消息會(huì)根據(jù)isa指針查找消息對(duì)象,這時(shí)會(huì)在method       Lists中遍歷,如果cache了,常用的方法調(diào)用時(shí)就能夠提高調(diào)用的效率。
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 協(xié)議鏈表
#endif

} OBJC2_UNAVAILABLE;
//OC中一個(gè)類(lèi)的對(duì)象實(shí)例的數(shù)據(jù)結(jié)構(gòu)(/usr/include/objc/objc.h)

OC中一個(gè)類(lèi)的對(duì)象實(shí)例的數(shù)據(jù)結(jié)構(gòu)(/usr/include/objc/objc.h):

typedef struct objc_class *Class;
// Represents an instance of a class.
struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};
// A pointer to an instance of a class.
typedef struct objc_object *id;

向object發(fā)送消息時(shí),Runtime庫(kù)會(huì)根據(jù)object的isa指針找到這個(gè)實(shí)例object所屬于的類(lèi),然后在類(lèi)的方法列表以及父類(lèi)方法列表尋找對(duì)應(yīng)的方法運(yùn)行。id是一個(gè)objc_object結(jié)構(gòu)類(lèi)型的指針,這個(gè)類(lèi)型的對(duì)象能夠轉(zhuǎn)換成任何一種對(duì)象。

然后再來(lái)看看消息發(fā)送的函數(shù):objc_msgSend函數(shù)

在引言中已經(jīng)對(duì)objc_msgSend進(jìn)行了一點(diǎn)介紹,看起來(lái)像是objc_msgSend返回了數(shù)據(jù),其實(shí)objc_msgSend從不返回?cái)?shù)據(jù)而是你的方法被調(diào)用后返回了數(shù)據(jù)。下面詳細(xì)敘述下消息發(fā)送步驟:

檢測(cè)這個(gè) selector 是不是要忽略的。比如 Mac OS X 開(kāi)發(fā),有了垃圾回收就不理會(huì) retain,release 這些函數(shù)了。
檢測(cè)這個(gè) target 是不是 nil 對(duì)象。ObjC 的特性是允許對(duì)一個(gè) nil 對(duì)象執(zhí)行任何一個(gè)方法不會(huì) Crash,因?yàn)闀?huì)被忽略掉。
如果上面兩個(gè)都過(guò)了,那就開(kāi)始查找這個(gè)類(lèi)的 IMP,先從 cache 里面找,完了找得到就跳到對(duì)應(yīng)的函數(shù)去執(zhí)行。
如果 cache 找不到就找一下方法分發(fā)表。
如果分發(fā)表找不到就到超類(lèi)的分發(fā)表去找,一直找,直到找到NSObject類(lèi)為止。

7、什么是method swizzling?
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è)類(lèi)都有一個(gè)方法列表,存放著selector的名字和方法實(shí)現(xiàn)的映射關(guān)系。IMP有點(diǎn)類(lèi)似函數(shù)指針,指向具體的Method實(shí)現(xiàn)。

方法指向

我們可以利用 method_exchangeImplementations 來(lái)交換2個(gè)方法中的IMP,

我們可以利用 class_replaceMethod 來(lái)修改類(lèi),

我們可以利用 method_setImplementation 來(lái)直接設(shè)置某個(gè)方法的IMP,
歸根結(jié)底,都是偷換了selector的IMP

8、instrument可以干什么?
Blank(空模板):創(chuàng)建一個(gè)空的模板,可以從Library庫(kù)中添加其他模板;
Activity Monitor(活動(dòng)監(jiān)視器):顯示器處理的CPU、內(nèi)存和網(wǎng)絡(luò)使用情況統(tǒng)計(jì);
Allocations(內(nèi)存分配):跟蹤過(guò)程的匿名虛擬內(nèi)存和堆的對(duì)象提供類(lèi)名和可選保留/釋放歷史;
Automation(自動(dòng)化):這個(gè)模板執(zhí)行它模擬用戶(hù)界面交互為IOS機(jī)應(yīng)用從instrument啟動(dòng)的腳本;
Leaks(泄漏):一般的措施內(nèi)存使用情況,檢查泄漏的內(nèi)存,并提供了所有活動(dòng)的分配和泄漏模塊的類(lèi)對(duì)象分配統(tǒng)計(jì)信息以及內(nèi)存地址歷史記錄;
Time Profiler(時(shí)間探查):執(zhí)行對(duì)系統(tǒng)的CPU上運(yùn)行的進(jìn)程低負(fù)載時(shí)間為基礎(chǔ)采樣。

推薦??:

  • 結(jié)實(shí)人脈、討論技術(shù) 你想要的這里都有!

  • 搶先入群,跑贏(yíng)同齡人!(入群無(wú)需任何費(fèi)用)

  • (直接搜索群號(hào):761407670,快速入群)

  • 點(diǎn)擊加入:iOS開(kāi)發(fā)交流群

整理的2020年《大廠(chǎng)最新常問(wèn)iOS面試題+答案》,有需要的伙伴,直接加iOS技術(shù)交流群:761407670,免費(fèi)獲??;群內(nèi)更有內(nèi)推機(jī)會(huì)!

申請(qǐng)即送:

BAT大廠(chǎng)面試題、獨(dú)家面試工具包,

資料免費(fèi)領(lǐng)取,包括 數(shù)據(jù)結(jié)構(gòu)、底層進(jìn)階、圖形視覺(jué)、音視頻、架構(gòu)設(shè)計(jì)、逆向安防、RxSwift、flutter,

作者:有度YouDo
原文鏈接:http://www.itdecent.cn/p/d2d8cf4e6ff6

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容