【2018最新】iOS面試題(一)

1.為什么OC是一門動(dòng)態(tài)語(yǔ)言??

動(dòng)態(tài)類型:OC在運(yùn)行時(shí)決定對(duì)象的類型,比如id;?

動(dòng)態(tài)綁定:程序在運(yùn)行時(shí)判斷需要調(diào)用的方法,而不是在編譯時(shí);?

動(dòng)態(tài)載入:程序在運(yùn)行時(shí)根據(jù)需要再加載可執(zhí)行的代碼和資源。

2.設(shè)計(jì)模式是什么?你知道哪些設(shè)計(jì)模式?簡(jiǎn)要敘述。?

設(shè)計(jì)模式是一種解決問(wèn)題的思維,通過(guò)設(shè)計(jì)模式達(dá)到可復(fù)用、可拓展的目的,盡量實(shí)現(xiàn)高內(nèi)聚低耦合。?

代理模式:用于回調(diào)數(shù)據(jù)。?

觀察者模式:當(dāng)對(duì)象的某個(gè)屬性發(fā)生改變時(shí),得到通知,進(jìn)行處理。?

單例模式:確保給定的類只有一個(gè)實(shí)例存在,通常用于懶加載的方式在第一次用到實(shí)例的時(shí)候再去創(chuàng)建它。?

工廠模式:根據(jù)傳入的參數(shù),動(dòng)態(tài)決定創(chuàng)建類的實(shí)例,比如NSNumber。

3.為什么代理要用weak?代理的delegate和dataSource有什么區(qū)別?block和代理的區(qū)別??

通過(guò)weak打破循環(huán)引用。?

delegate是一個(gè)類委托另一個(gè)類實(shí)現(xiàn)某個(gè)方法,協(xié)議里面的方法主要是與操作相關(guān)的。?

datasource一個(gè)類通過(guò)datasource將數(shù)據(jù)發(fā)送給需要接受委托的類,協(xié)議里面的方法主要是跟內(nèi)容有關(guān)的。?

代理和block的區(qū)別:代理和block的共同特性是回調(diào)機(jī)制。不同的是代理的方法比較多,block代碼比較集中;代理的運(yùn)行成本要低于block的運(yùn)行成本,block的出站需要從棧內(nèi)存拷貝到堆內(nèi)存。公共接口比較多時(shí),用代理解耦;簡(jiǎn)單回調(diào)和異步線程中使用block。

4.屬性的實(shí)質(zhì)是什么?包括哪幾個(gè)部分?屬性默認(rèn)的關(guān)鍵字有哪些?@dynamic關(guān)鍵字和@synthesize關(guān)鍵字是做什么的??

屬性的實(shí)質(zhì)是成員變量+存取方法。包括三部分ivar+getter+setter。屬性默認(rèn)的關(guān)鍵字有strong、assgin、weak、unsafe_unretaind、nonatomic、atomic。使用@dynamic關(guān)鍵字,需要手動(dòng)添加getter、setter方法,@synthesize自動(dòng)生成setter、getter方法。

5.OC的類可以多繼承嗎?可以實(shí)現(xiàn)多個(gè)接口嗎?Category是什么?重寫一個(gè)類的方法用繼承好還是Category好?為什么??

OC中的類只能單繼承,可以通過(guò)協(xié)議實(shí)現(xiàn)多個(gè)接口。Category是分類,分類中的方法具有最高優(yōu)先級(jí)。重寫類的方法的時(shí)候分情況使用,如果只有你個(gè)人的類中需要重寫某個(gè)方法,那用繼承比較好,因?yàn)镃ategory中方法優(yōu)先級(jí)的原因,使用Category重寫方法,可能導(dǎo)致團(tuán)隊(duì)合作中,其他成員引入該類后出現(xiàn)問(wèn)題。如果該需求涉及到團(tuán)隊(duì)中多個(gè)任務(wù),可以通過(guò)Category重寫該方法。

6.可變集合類和不可變集合類的copy和mutablecopy有什么區(qū)別?如果是集合內(nèi)容復(fù)制的話,里面的元素也會(huì)一起復(fù)制嗎??

可變集合類中copy和mutablecopy都是深拷貝,不可變集合中copy是淺拷貝,mutablecopy是深拷貝。元素不會(huì)一起復(fù)制,如果需要拷貝的集合中,層級(jí)比較深,使用歸檔的方法,可以做元素的全部拷貝。

7.nonatomic和atomic的區(qū)別?atomic是絕對(duì)的線程安全嗎?為什么?如果不是,那應(yīng)該如何實(shí)現(xiàn)??

nonatomic和atomic是原子屬性,nonatomic是不是線程安全的,atomic是線程安全的。atomic不是絕對(duì)的線程安全,假設(shè)有三個(gè)線程,一個(gè)線程進(jìn)行寫入操作,一個(gè)線程進(jìn)行讀取操作,一個(gè)線程進(jìn)行寫入操作。如果使用atomic,在讀取完成之前,值可能會(huì)被篡改。使用柵欄塊(dispatch_barrier_async)解決。

8.用storyboard開發(fā)界面有什么弊端?如何避免??

storyboard開發(fā)界面時(shí)速度較快,但是后期版本更新迭代時(shí),維護(hù)成本過(guò)高;多人協(xié)作開發(fā)過(guò)程中,沖突問(wèn)題較多。為了避免更好的維護(hù)代碼,storyboard更適合用來(lái)描述viewcontroller之間的關(guān)系;xib進(jìn)行簡(jiǎn)單視圖繪制;手動(dòng)編碼繪制共同性較高的視圖,這樣可提高移植性和降低維護(hù)成本。

9.你是否接觸過(guò)OC中的反射機(jī)制?簡(jiǎn)單聊一下概念和使用??

OC的反射機(jī)制分為Class反射和SEL反射兩種,Class的反射是實(shí)現(xiàn)類名的字符串形式實(shí)例化對(duì)象和把類名變成字符串;SEL的反射是實(shí)現(xiàn)方法的字符串形式實(shí)例化方法和將方法變成字符串。?

如果我們要實(shí)現(xiàn)一個(gè)場(chǎng)景,根據(jù)不同情況實(shí)現(xiàn)某個(gè)頁(yè)面進(jìn)行轉(zhuǎn)場(chǎng),用OC的反射機(jī)制,通過(guò)runtime實(shí)現(xiàn)該需求最好。

10.數(shù)據(jù)持久化的幾個(gè)方案(fmdb用沒(méi)用過(guò))?

沙盒、鑰匙串、文件存儲(chǔ)、數(shù)據(jù)庫(kù)存儲(chǔ)?

小規(guī)模數(shù)據(jù),弱業(yè)務(wù)相關(guān)的數(shù)據(jù)放在沙盒中;生成的UUID等需要加密的非常小的數(shù)據(jù)保存在鑰匙串里面;文件存儲(chǔ)包括了plist、archive、stream等方式,一般需要方便查詢的數(shù)據(jù),會(huì)以plist的方式存儲(chǔ)、archive適合平時(shí)很少使用,但數(shù)據(jù)量很大的數(shù)據(jù)、stream用來(lái)存儲(chǔ)圖片等數(shù)據(jù)量不算太大的那種;當(dāng)數(shù)據(jù)有狀態(tài)和類別等強(qiáng)業(yè)務(wù)相關(guān)的時(shí)候,采用數(shù)據(jù)庫(kù)方案比較好。

11.block的實(shí)質(zhì)是什么?一共有幾種block?都是什么情況下生成的??

block實(shí)質(zhì)上是一個(gè)指向結(jié)構(gòu)體的指針。一共有三種block,棧上的block,堆上的block,全局的block。在ARC中,block中如果對(duì)捕獲的全局變量進(jìn)行操作或是未對(duì)捕獲的外部變量進(jìn)行操作,則該block為全局block;block中如果對(duì)捕獲的棧上或堆上的變量進(jìn)行操作,則該block為堆上的block。block中如果既對(duì)全局變量進(jìn)行操作,也對(duì)其他內(nèi)存區(qū)變量進(jìn)行操作,則該block為堆上的block。

12.objc在向一個(gè)對(duì)象發(fā)送消息時(shí),發(fā)生了什么??

objc在向一個(gè)對(duì)象發(fā)送消息時(shí),runtime庫(kù)會(huì)根據(jù)對(duì)象的isa指針找到對(duì)象實(shí)際所屬的類,然后在該類中的方法列表及父類方法列表中尋找方法并運(yùn)行。如果在最頂層的父類中依然沒(méi)找到方法,objc會(huì)調(diào)用resolveInstanceMethod:方法,讓我們動(dòng)態(tài)為該對(duì)象添加一個(gè)函數(shù)實(shí)現(xiàn);如果在該方法中仍沒(méi)有找到對(duì)應(yīng)的方法,objc會(huì)調(diào)用forwardingTargetForSelector方法,將該消息轉(zhuǎn)發(fā)給其他對(duì)象;如果在調(diào)用該方法后仍沒(méi)找到對(duì)應(yīng)方法,首先會(huì)調(diào)用methodSignatureForSelector方法,獲得需要實(shí)現(xiàn)函數(shù)的參數(shù)和返回值類型,如果該消息返回nil則調(diào)用doesNotRecognizeSelector方法,程序崩潰,如果返回了函數(shù)簽名,runtime會(huì)創(chuàng)建NSInvocation對(duì)象,并調(diào)用forwardInvocation方法給目標(biāo)對(duì)象。

13.runtime如何實(shí)現(xiàn)weak變量自動(dòng)置nil??

runtime維護(hù)了一個(gè)weak表,用于存儲(chǔ)指向某個(gè)對(duì)象的所有weak指針。weak表是一個(gè)哈希表,key是所指對(duì)象的地址,value是所有指向該對(duì)象的weak指針的地址構(gòu)成的數(shù)組。當(dāng)該對(duì)象的引用計(jì)數(shù)為0時(shí),則遍歷指向該對(duì)象的weak指針的地址所構(gòu)成的數(shù)組,并置為nil。

例如 {id __weak obj1 = obj}通過(guò)偽代碼實(shí)現(xiàn):?

定義函數(shù)objc_storeWeak(value,key);第一個(gè)參數(shù)為__weak修飾的變量obj1的地址,第二個(gè)參數(shù)為賦值對(duì)象obj的地址,如果第二個(gè)參數(shù)為0,則將變量的地址從weak表中刪除。?

id obj1 = 5;?

objc_storeWeak(&obj1,&obj);?

objc_storeWeak(&obj1,0);

14.runloop是用來(lái)做什么的?runloop和線程有什么關(guān)系?主線程默認(rèn)開啟了runloop嗎?子線程呢??

程序啟動(dòng)的時(shí)候會(huì)開辟一個(gè)主線程并將該線程添加到runloop中,保證主線程不被銷毀,程序持續(xù)運(yùn)行;處理應(yīng)用中的各種事件;如果應(yīng)用處于休眠狀態(tài),則釋放資源,提高系統(tǒng)運(yùn)行效率。?

runloop和線程是一對(duì)一的關(guān)系,他們之間的關(guān)系保存在全局字典中;線程不會(huì)自動(dòng)創(chuàng)建runloop;對(duì)應(yīng)線程結(jié)束時(shí),runloop會(huì)被銷毀。?

主線程默認(rèn)開啟了runloop。?

子線程沒(méi)有,需要我們手動(dòng)獲取runloop以后,將子線程添加到runloop中。

15.為什么把NSTimer對(duì)象以NSDefaultRunLoopMode添加到主運(yùn)行循環(huán)以后,滑動(dòng)scrollview的時(shí)候,NSTimer卻不動(dòng)了。?

滑動(dòng)scrollview時(shí),蘋果開發(fā)為了保證界面優(yōu)先原則,runloop切換到UITrackingRunLoopMode模式。將模式設(shè)置為kCFRunloopCommonModes就可以保證滑動(dòng)scrollview時(shí),NSTimer也繼續(xù)走動(dòng)。

16.KVO的使用?實(shí)現(xiàn)原理?(為什么要?jiǎng)?chuàng)建子類來(lái)實(shí)現(xiàn))?

讓A對(duì)象監(jiān)聽B對(duì)象的屬性,當(dāng)B對(duì)象的屬性發(fā)生改變時(shí),A對(duì)象收到通知。

KVO的實(shí)現(xiàn)原理:當(dāng)觀察對(duì)象B時(shí),KVO會(huì)通過(guò)OC的runtime動(dòng)態(tài)創(chuàng)建一個(gè)對(duì)象B當(dāng)前類的子類,并為這個(gè)新的子類重寫被觀察屬性的setter方法,setter方法隨后負(fù)責(zé)通知觀察對(duì)象屬性的改變狀況。KVO是通過(guò)setter方法實(shí)現(xiàn)的,需要使用self.來(lái)修改屬性對(duì)象的成員變量才會(huì)有效,直接通過(guò)成員變量復(fù)制不會(huì)觸發(fā)KVO機(jī)制。

17.KVC的使用?實(shí)現(xiàn)原理?(KVC拿到key以后,是如何賦值的?知不知道集合操作符?能不能訪問(wèn)私有屬性?能不能直接訪問(wèn)_ivar)?

KVC提供了一種間接訪問(wèn)其屬性方法或成員變量的機(jī)制,可以通過(guò)字符串來(lái)訪問(wèn)對(duì)應(yīng)的屬性或成員變量,通過(guò)valueForKey實(shí)現(xiàn)getter方法的讀取,通過(guò)setValue:forKey:實(shí)現(xiàn)setter方法的賦值,以及衍生出的keyPath方法。

KVC的實(shí)現(xiàn)原理:?

當(dāng)一個(gè)對(duì)象調(diào)用setValue方法時(shí),方法內(nèi)部會(huì)做以下操作:?

1). 檢查是否存在相應(yīng)的key的set方法,如果存在,就調(diào)用set方法。?

2). 如果set方法不存在,就會(huì)查找與key相同名稱并且?guī)聞澗€的成員變量,如果有,則直接給成員變量屬性賦值。?

3). 如果沒(méi)有找到_key,就會(huì)查找相同名稱的屬性key,如果有就直接賦值。?

4). 如果還沒(méi)有找到,則調(diào)用valueForUndefinedKey:和setValue:forUndefinedKey:方法。?

這些方法的默認(rèn)實(shí)現(xiàn)都是拋出異常,我們可以根據(jù)需要重寫它們。

最后編輯于
?著作權(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)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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