那些著名或非著名的iOS面試題(下)
那些著名或非著名的iOS面試題(下)
1. Runtime
Objective-C 是面相執行時的語言(runtime oriented language),就是說它會盡可能的把編譯和連結時要執行的邏輯延遲到執行時。這就給了你很大的靈活性,你可以按需要把訊息重定向給合適的物件,你甚 至可以交換方法的實現,等等。
RunTime簡稱執行時。就是系統在執行的時候的一些機制,其中最主要的是訊息機制。OC的函式呼叫成為訊息傳送。屬於動態呼叫過程。在編譯的時候並不能決定真正呼叫哪個函式(事實證明,在編 譯階段,OC可以呼叫任何函式,即使這個函式並未實現,只要申明過就不會報錯。而C語言在編譯階段就會報錯)。只有在真正執行的時候才會根據函式的名稱找 到對應的函式來呼叫。
以下面的程式碼為例:
[obj makeText];
其中obj是一個物件,makeText是一個函式名稱。對於這樣一個簡單的呼叫。在編譯時RunTime會將上述程式碼轉化成
objc_msgSend(obj,@selector(makeText));
首先,編譯器將程式碼[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中的函式指標跳轉到對應的函式中去執行。
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。
2. GCD實現1,2並行和3序列和45序列,4,5是並行。即3依賴1,2的執行,45依賴3的執行。
佇列組的方式
- (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); }); }); }
序列佇列:佇列中的任務只會順序執行
dispatch_queue_t q = dispatch_queue_create(“....”, dispatch_queue_serial);
並行佇列: 佇列中的任務通常會併發執行。
dispatch_queue_t q = dispatch_queue_create("......", dispatch_queue_concurrent);
全域性佇列:是系統開發的,直接拿過來用就可以;與並行佇列類似,但除錯時,無法確認操作所在佇列 。
dispatch_queue_t q = dispatch_get_global_queue(dispatch_queue_priority_default, 0);
主佇列:每一個應用開發程式對應唯一一個主佇列,直接get即可;在多執行緒開發中,使用主佇列更新UI。
dispatch_queue_t q = dispatch_get_main_queue();
主佇列是GCD自帶的序列佇列,會在主執行緒中執行。非同步全域性併發佇列 開啟新執行緒,併發執行。
並行佇列裡開啟同步任務是有執行順序的,只有非同步才沒有順序。
序列佇列開啟非同步任務,是有順序的。
序列佇列開啟非同步任務後巢狀同步任務造成死鎖。
3. 深淺複製和屬性為copy,strong值的變化問題
淺複製:只複製指向物件的指標,而不復制引用物件本身。對於淺複製來說,A和A_copy指向的是同一個記憶體資源,複製的只不個是一個指標,物件本身資源還是隻有一份,那如果我們對A_copy執行了修改操作,那麼發現A引用的物件同樣被修改了。深複製就好理解了,記憶體中存在了兩份獨立物件本身。
在Objective-C中並不是所有的物件都支援Copy,MutableCopy,遵守NSCopying協議的類才可以傳送Copy訊息,遵守NSMutableCopying協議的類才可以傳送MutableCopy訊息。
[immutableObject copy] // 淺拷貝
[immutableObject mutableCopy] //深拷貝
[mutableObject copy] //深拷貝
[mutableObject mutableCopy] //深拷貝
屬性設為copy,指定此屬性的值不可更改,防止可變字串更改自身的值的時候不會影響到物件屬性(如NSString,NSArray,NSDictionary)的值。strong此屬性的指會隨著變化而變化。copy是內容拷貝,strong是指標拷貝。
4.NSTimer建立後,會在哪個執行緒執行。
用scheduledTimerWithTimeInterval建立的,在哪個執行緒建立就會被加入哪個執行緒的RunLoop中就執行在哪個執行緒。
自己建立的Timer,加入到哪個執行緒的RunLoop中就執行在哪個執行緒。
5. 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是弱關聯,利好訊息發出,你不需要知道是誰發的也可以做出相應的反應,同理發訊息的人也不需要知道接收的人也可以正常發出訊息。
6. 如何讓計時器呼叫一個類方法
計時器只能呼叫例項方法,但是可以在這個例項方法裡面呼叫靜態方法。
使用計時器需要注意,計時器一定要加入RunLoop中,並且選好model才能執行。scheduledTimerWithTimeInterval方法建立一個計時器並加入到RunLoop中所以可以直接使用。
如果計時器的repeats選擇YES說明這個計時器會重複執行,一定要在合適的時機呼叫計時器的invalid。不能在dealloc中呼叫,因為一旦設定為repeats 為yes,計時器會強持有self,導致dealloc永遠不會被呼叫,這個類就永遠無法被釋放。比如可以在viewDidDisappear中呼叫,這樣當類需要被回收的時候就可以正常進入dealloc中了。
7. 呼叫一個類的靜態方法需不需要release?
靜態方法,就是類方法,不需要,類方法物件放在autorelease中
8. static作用?
(1)函式體內 static 變數的作用範圍為該函式體,不同於 auto 變數,該變數的記憶體只被分配一次,因此其值在下次呼叫時仍維持上次的值;
(2)在模組內的 static 全域性變數可以被模組內所用函式訪問,但不能被模組外其它函式訪問;
(3)在模組內的 static 函式只可被這一模組內的其它函式呼叫,這個函式的使用範圍被限制在宣告
它的模組內;
(4)在類中的 static 成員變數屬於整個類所擁有,對類的所有物件只有一份拷貝;
(5)在類中的 static 成員函式屬於整個類所擁有,這個函式不接收 this 指標,因而只能訪問類的static 成員變數。
9. 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要略微廣泛一些。可用來做一些初始化工作,或者單例模式的一種實現方案。
10. 能否向編譯後得到的類中增加例項變數?能否向執行時建立的類中新增例項變數?為什麼?
不能向編譯後得到的類中增加例項變數;
能向執行時建立的類中新增例項變數;
因為編譯後的類已經註冊在 runtime 中,類結構體中的 objc_ivar_list 例項變數的連結串列 和 instance_size 例項變數的記憶體大小已經確定,同時runtime 會呼叫 class_setIvarLayout 或 class_setWeakIvarLayout 來處理 strong weak 引用。所以不能向存在的類中新增例項變數;
執行時建立的類是可以新增例項變數,呼叫 class_addIvar 函式。但是得在呼叫 objc_allocateClassPair 之後,objc_registerClassPair 之前,原因同上。
相關文章
- 那些著名或非著名的iOS面試題(上)iOS面試題
- 那些著名或非著名的iOS面試題(中)iOS面試題
- 那些著名或非著名的iOS面試題-前編iOS面試題
- 那些著名或非著名的iOS面試題-中編iOS面試題
- 著名埠
- Python 計算生態中那些著名的庫-機器學習Python機器學習
- Python 計算生態中那些著名的庫-文字處理Python
- iOS開發之一些著名開發者部落格iOS
- 著名的維客(wiki)網站網站
- 解決github中一個新手著名問題Github
- 著名 Emacs 使用者列表Mac
- 著名程式設計語錄程式設計
- Python 計算生態中那些著名的庫-資料視覺化Python視覺化
- 破解DVD格式,就是著名的DECSS (轉)CSS
- 著名網際網路大廠PM面試指南資料清單面試
- 著名駭客釋出基於網頁的盤古iOS9.3.3越獄網頁iOS
- LINUX&UNIX 中文著名網站Linux網站
- ORACLE函式介紹第四篇 非著名函式之聚合函式Oracle函式
- 幾個世界著名的網站安全站點網站
- ORACLE函式介紹第二篇 非著名函式之單值函式Oracle函式
- ORACLE函式介紹第七篇 非著名函式之分析函式Oracle函式
- 著名安全專家Litchfield對Oracle開火Oracle
- ios 面試那些事iOS面試
- 微軟補丁帶來新問題 著名駭客提建議(轉)微軟
- GitHub最著名的20個Python機器學習專案!GithubPython機器學習
- 著名AI風投、學術機構和公司AI
- SEOer不能不知的國外著名的SEO網站網站
- 幾種著名的戰略思想設計工具介紹 - Chris
- 能為你指明方向的著名程式設計語錄程式設計
- 警惕:高考將至著名高校網站被掛馬網站
- 著名美國電信公司招聘linux kernel engineer(轉)Linux
- 著名部落格網站TechCrunch挖來福克斯高管掌舵網站
- 這些著名資料庫之間的“關係”,你知道嗎?資料庫
- 世界著名雲服務SaaS公司的開源替代專案列表
- 著名律師萊布尼茨的手搖式計算機計算機
- 著名黑客雷蒙評價最重要的幾種程式語言黑客
- 著名程式語言Fortran創始人貝克斯辭世
- 著名軟體大師Chris Richardson訪談問題有獎徵集(圖靈訪談)圖靈