iOS部分經典面試題

一、Runtime面試

Objective-C 是面相運行時的語言(runtime oriented language),就是說它會盡量的把編譯和連接時要執行的邏輯延遲到運行時。這就給了你很大的靈活性,你能夠按須要把消息重定向給合適的對象,你甚 至能夠交換方法的實現,等等。算法

RunTime簡稱運行時。就是系統在運行的時候的一些機制,其中最主要的是消息機制。OC的函數調用成爲消息發送。屬於動態調用過程。在編譯的時候並不能決定真正調用哪一個函數(事實證實,在編 譯階段,OC能夠調用任何函數,即便這個函數並未實現,只要申明過就不會報錯。而C語言在編譯階段就會報錯)。只有在真正運行的時候纔會根據函數的名稱找 到對應的函數來調用。編程

如下面的代碼爲例:swift

[Objective-C] 純文本查看 複製代碼安全

[obj makeText];

複製代碼

其中obj是一個對象,makeText是一個函數名稱。對於這樣一個簡單的調用。在編譯時RunTime會將上述代碼轉化成markdown

[Objective-C] 純文本查看 複製代碼數據結構

objc_msgSend(obj,@selector(makeText));

複製代碼

做爲一個開發者,有一個學習的氛圍跟一個交流圈子特別重要,這是一個個人iOS交流羣:834688868,無論你是小白仍是大牛歡迎入駐 ,分享BAT,阿里面試題、面試經驗,討論技術, 你們一塊兒交流學習成長!多線程

羣內提供數據結構與算法、底層進階、swift、逆向、flutter,音視頻等整合面試題等免費獲取 另外贈附21年最新收集的各大廠面試題(附答案) 羣文件直接獲取!併發

首先,編譯器將代碼[obj makeText];轉化爲objc_msgSend(obj, @selector (makeText));,在objc_msgSend函數中。首先經過obj的isa指針找到obj對應的class。在Class中先去cache中 經過SEL查找對應函數method(猜想cache中method列表是以SEL爲key經過hash表來存儲的,這樣能提升函數查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,則取superClass中查找。若能找到,則將method加 入到cache中,以方便下次查找,並經過method中的函數指針跳轉到對應的函數中去執行。app

Objective-C Runtime 是什麼?

Objective-C 的 Runtime 是一個運行時庫(Runtime Library),它是一個主要使用 C 和彙編寫的庫,爲 C 添加了面相對象的能力並創造了 Objective-C。這就是說它在類信息(Class information) 中被加載,完成全部的方法分發,方法轉發,等等。Objective-C runtime 建立了全部須要的結構體,讓 Objective-C 的面相對象編程變爲可能。

Method Swizzling 原理

在Objective-C中調用一個方法,實際上是向一個對象發送消息,查找消息的惟一依據是selector的名字。利用Objective-C的動態特性,能夠實如今運行時偷換selector對應的方法實現,達到給方法掛鉤的目的。每一個類都有一個方法列表,存放着selector的名字和方法實現的映射關係。IMP有點相似函數指針,指向具體的Method實現。

咱們能夠利用 method_exchangeImplementations 來交換2個方法中的IMP,

咱們能夠利用 class_replaceMethod 來修改類,

咱們能夠利用 method_setImplementation 來直接設置某個方法的IMP,……

歸根結底,都是偷換了selector的IMP。

二、GCD實現1,2並行和3串行和45串行,4,5是並行。即3依賴1,2的執行,45依賴3的執行。

<ignore_js_op>[圖片上傳中...(image-967340-1554465993329-0)]</ignore_js_op>

關係

隊列組的方式

[Objective-C] 純文本查看 複製代碼

- (void) methodone{
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"%d",1);
});

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"%d",2);
});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"3");

    dispatch_group_t group1 = dispatch_group_create();

    dispatch_group_async(group1, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"%d",4);
    });

    dispatch_group_async(group1, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"%d",5);
    });

});

}

複製代碼

串行隊列:隊列中的任務只會順序執行

[Objective-C] 純文本查看 複製代碼

dispatch_queue_t q = dispatch_queue_create(「....」, dispatch_queue_serial);

複製代碼

並行隊列: 隊列中的任務一般會併發執行。

[Objective-C] 純文本查看 複製代碼

dispatch_queue_t q = dispatch_queue_create("......", dispatch_queue_concurrent);

複製代碼

全局隊列:是系統開發的,直接拿過來用就能夠;與並行隊列相似,但調試時,沒法確認操做所在隊列 。

[Objective-C] 純文本查看 複製代碼

dispatch_queue_t q = dispatch_get_global_queue(dispatch_queue_priority_default, 0);

複製代碼

主隊列:每個應用開發程序對應惟一一個主隊列,直接get便可;在多線程開發中,使用主隊列更新UI。

[Objective-C] 純文本查看 複製代碼

dispatch_queue_t q = dispatch_get_main_queue();

複製代碼

主隊列是GCD自帶的串行隊列,會在主線程中執行。異步全局併發隊列 開啓新線程,併發執行。

並行隊列裏開啓同步任務是有執行順序的,只有異步纔沒有順序。

串行隊列開啓異步任務,是有順序的。

串行隊列開啓異步任務後嵌套同步任務形成死鎖。

三、深淺複製和屬性爲copy,strong值的變化問題

淺複製:只複製指向對象的指針,而不復制引用對象自己。對於淺複製來講,A和A_copy指向的是同一個內存資源,複製的只不個是一個指針,對象自己資源仍是隻有一份,那若是咱們對A_copy執行了修改操做,那麼發現A引用的對象一樣被修改了。深複製就好理解了,內存中存在了兩份獨立對象自己。

在Objective-C中並非全部的對象都支持Copy,MutableCopy,遵照NSCopying協議的類才能夠發送Copy消息,遵照NSMutableCopying協議的類才能夠發送MutableCopy消息。

[Objective-C] 純文本查看 複製代碼

[immutableObject copy] // 淺拷貝
[immutableObject mutableCopy] //深拷貝
[mutableObject copy] //深拷貝
[mutableObject mutableCopy] //深拷貝

複製代碼

屬性設爲copy,指定此屬性的值不可更改,防止可變字符串更改自身的值的時候不會影響到對象屬性(如NSString,NSArray,NSDictionary)的值。strong此屬性的指會隨着變化而變化。copy是內容拷貝,strong是指針拷貝。

四、NSTimer建立後,會在哪一個線程運行。

用scheduledTimerWithTimeInterval建立的,在哪一個線程建立就會被加入哪一個線程的RunLoop中就運行在哪一個線程。

本身建立的Timer,加入到哪一個線程的RunLoop中就運行在哪一個線程。

五、KVO,NSNotification,delegate及block區別

KVO就是cocoa框架實現的觀察者模式,通常同KVC搭配使用,經過KVO能夠監測一個值的變化,好比View的高度變化。是一對多的關係,一個值的變化會通知全部的觀察者。

NSNotification是通知,也是一對多的使用場景。在某些狀況下,KVO和NSNotification是同樣的,都是狀態變化以後告知對方。NSNotification的特色,就是須要被觀察者先主動發出通知,而後觀察者註冊監聽後再來進行響應,比KVO多了發送通知的一步,可是其優勢是監聽不侷限於屬性的變化,還能夠對多種多樣的狀態變化進行監聽,監聽範圍廣,使用也更靈活。

delegate 是代理,就是我不想作的事情交給別人作。好比狗須要吃飯,就經過delegate通知主人,主人就會給他作飯、盛飯、倒水,這些操做,這些狗都不須要關心,只須要調用delegate(代理人)就能夠了,由其餘類完成所須要的操做。因此delegate是一對一關係。

block是delegate的另外一種形式,是函數式編程的一種形式。使用場景跟delegate同樣,相比delegate更靈活,並且代理的實現更直觀。

KVO通常的使用場景是數據,需求是數據變化,好比股票價格變化,咱們通常使用KVO(觀察者模式)。delegate通常的使用場景是行爲,需求是須要別人幫我作一件事情,好比買賣股票,咱們通常使用delegate。Notification通常是進行全局通知,好比利好消息一出,通知你們去買入。delegate是強關聯,就是委託和代理雙方互相知道,你委託別人買股票你就須要知道經紀人,經紀人也不要知道本身的顧客。Notification是弱關聯,利好消息發出,你不須要知道是誰發的也能夠作出相應的反應,同理發消息的人也不須要知道接收的人也能夠正常發出消息。

六、如何讓計時器調用一個類方法

計時器只能調用實例方法,可是能夠在這個實例方法裏面調用靜態方法。

使用計時器須要注意,計時器必定要加入RunLoop中,而且選好model才能運行。scheduledTimerWithTimeInterval方法建立一個計時器並加入到RunLoop中因此能夠直接使用。

若是計時器的repeats選擇YES說明這個計時器會重複執行,必定要在合適的時機調用計時器的invalid。不能在dealloc中調用,由於一旦設置爲repeats 爲yes,計時器會強持有self,致使dealloc永遠不會被調用,這個類就永遠沒法被釋放。好比能夠在viewDidDisappear中調用,這樣當類須要被回收的時候就能夠正常進入dealloc中了。

七、調用一個類的靜態方法需不須要release?

靜態方法,就是類方法,不須要,類方法對象放在autorelease中

八、static做用?

(1)函數體內 static 變量的做用範圍爲該函數體,不一樣於 auto 變量,該變量的內存只被分配一次,所以其值在下次調用時仍維持上次的值;

(2)在模塊內的 static 全局變量能夠被模塊內所用函數訪問,但不能被模塊外其它函數訪問;

(3)在模塊內的 static 函數只可被這一模塊內的其它函數調用,這個函數的使用範圍被限制在聲明

它的模塊內;

(4)在類中的 static 成員變量屬於整個類所擁有,對類的全部對象只有一份拷貝;

(5)在類中的 static 成員函數屬於整個類所擁有,這個函數不接收 this 指針,於是只能訪問類的static 成員變量。

九、NSObject的load和initialize方法

load和initialize的共同特色

在不考慮開發者主動使用的狀況下,系統最多會調用一次

若是父類和子類都被調用,父類的調用必定在子類以前

都是爲了應用運行提早建立合適的運行環境

在使用時都不要太重地依賴於這兩個方法,除非真正必要

load和initialize的區別

load方法

調用時機比較早,運行環境有不肯定因素。具體說來,在iOS上一般就是App啓動時進行加載,但當load調用的時候,並不能保證全部類都加載完成且可用,必要時還要本身負責作auto release處理。對於有依賴關係的兩個庫中,被依賴的類的load會優先調用。但在一個庫以內,調用順序是不肯定的。

對於一個類而言,沒有load方法實現就不會調用,不會考慮對NSObject的繼承。

一個類的load方法不用寫明[super load],父類就會收到調用,而且在子類以前。

Category的load也會收到調用,但順序上在主類的load調用以後。

不會直接觸發initialize的調用。

initialize方法相關要點

initialize的天然調用是在第一次主動使用當前類的時候。

在initialize方法收到調用時,運行環境基本健全。

initialize的運行過程當中是能保證線程安全的。

和load不一樣,即便子類不實現initialize方法,會把父類的實現繼承過來調用一遍。注意的是在此以前,父類的方法已經被執行過一次了,一樣不須要super調用。

因爲initialize的這些特色,使得其應用比load要略微普遍一些。可用來作一些初始化工做,或者單例模式的一種實現方案。

十、可否向編譯後獲得的類中增長實例變量?可否向運行時建立的類中添加實例變量?爲何?

不能向編譯後獲得的類中增長實例變量;

能向運行時建立的類中添加實例變量;

由於編譯後的類已經註冊在 runtime 中,類結構體中的 objc_ivar_list 實例變量的鏈表 和 instance_size 實例變量的內存大小已經肯定,同時runtime 會調用 class_setIvarLayout 或 class_setWeakIvarLayout 來處理 strong weak 引用。因此不能向存在的類中添加實例變量;

運行時建立的類是能夠添加實例變量,調用 class_addIvar 函數。可是得在調用 objc_allocateClassPair 以後,objc_registerClassPair 以前,緣由同上。

相關文章
相關標籤/搜索