前段時間更新了一篇 給iOS中高級面試官的一份招聘要求 收到不少小夥伴的點贊與關注。可能有不少小夥伴已經帶着我在那篇文章給你們提供的一些面試技巧 & 其中的面試題 已經開始招聘或者應聘了!這裏應你們要求,對裏面的面試題提供相關答案!相信不管是面試官仍是求職者都是有所收穫的~~html
PS:篇幅有點長,你們能夠關注或者點贊收藏以備不時之需!!!java
1:講講你對
atomic
&nonatomic
的理解ios
atomic
修飾的屬性(不重載設置器和訪問器)只保證了對數據讀寫的完整性,也就是原子性,可是與對象的線程安全無關。nonatomic
替代atomic
,固然也能夠一直使用atomic
。2:被
weak
修飾的對象在被釋放的時候會發生什麼?是如何實現的?知道sideTable
麼?裏面的結構能夠畫出來麼?git
被weak修飾的對象在被釋放時候會置爲nil,不一樣於assign;github
Runtime
維護了一個 weak表
,用於存儲指向某個對象的全部weak指針
。weak表
實際上是一個 hash(哈希)表
,Key
是所指對象的地址,Value
是 weak指針
的地址(這個地址的值是所指對象指針的地址)數組。web
runtime
會調用 objc_initWeak函數
,初始化一個新的 weak指針
指向對象的地址。objc_initWeak函數
會調用 objc_storeWeak() 函數
, objc_storeWeak()
的做用是更新指針指向,建立對應的弱引用表。clearDeallocating函數
。clearDeallocating函數
首先根據對象地址獲取全部 weak指針地址
的數組,而後遍歷這個數組把其中的數據設爲 nil
,最後把這個 entry
從 weak表
中刪除,最後清理對象的記錄。struct SideTable {
// 保證原子操做的自旋鎖
spinlock_t slock;
// 引用計數的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
}
struct weak_table_t {
// 保存了全部指向指定對象的 weak 指針
weak_entry_t *weak_entries;
// 存儲空間
size_t num_entries;
// 參與判斷引用計數輔助量
uintptr_t mask;
// hash key 最大偏移值
uintptr_t max_hash_displacement;
};
複製代碼
3:
block
用什麼修飾?strong
能夠?面試
block
自己是像對象同樣能夠 retain
,和 release
。可是,block
在建立的時候,它的內存是分配在棧(stack)上,而不是在堆(heap)上。他自己的做於域是屬於建立時候的做用域,一旦在建立時候的做用域外面調用block將致使程序崩潰。retain
也能夠,可是block的retain行爲默認是用copy的行爲實現的block
變量默認是聲明爲棧變量的,爲了可以在block的聲明域外使用,因此要把 block
拷貝(copy)到堆,因此說爲了 block
屬性聲明和實際的操做一致,最好聲明爲 copy
。4:
block
爲何可以捕獲外界變量?__block
作了什麼事?算法
研究Block的捕獲外部變量就要除去函數參數這一項,下面一一根據這4種變量類型的捕獲狀況進行分析。編程
首先 全局變量global_i
和 靜態全局變量static_global_j
的值增長,以及它們被Block
捕獲進去,這一點很好理解,由於是全局的,做用域很廣,因此Block
捕獲了它們進去以後,在Block
裏面進行++
操做,Block
結束以後,它們的值依舊能夠得以保存下來。設計模式
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
複製代碼
__main_block_impl_0結構體
就是這樣把自動變量捕獲進來的。也就是說,在執行 Block
語法的時候,Block
語法表達式所使用的自動變量的值是被保存進了Block
的結構體實例中,也就是 Block
自身中。
這裏值得說明的一點是,若是Block
外面還有不少自動變量,靜態變量,等等,這些變量在Block
裏面並不會被使用到。那麼這些變量並不會被Block
捕獲進來,也就是說並不會在構造函數裏面傳入它們的值。
Block
捕獲外部變量僅僅只捕獲Block
閉包裏面會用到的值,其餘用不到的值,它並不會去捕獲。
5:談談你對事件的傳遞鏈和響應鏈的理解
UIResponser
包括了各類Touch message
的處理,好比開始,移動,中止等等。常見的 UIResponser
有 UIView及子類
,UIViController
,APPDelegate
,UIApplication
等等。回到響應鏈,響應鏈是由UIResponser
組成的,那麼是按照哪一種規則造成的。
A: 程序啓動 UIApplication
會生成一個單例,並會關聯一個APPDelegate
。APPDelegate
做爲整個響應鏈的根創建起來,而``UIApplication會將本身與這個單例連接,即
UIApplication的
nextResponser(下一個事件處理者)爲
APPDelegate`。
B:建立UIWindow 程序啓動後,任何的UIWindow
被建立時,UIWindow
內部都會把nextResponser
設置爲UIApplication單例
。UIWindow
初始化rootViewController
,rootViewController
的nextResponser
會設置爲UIWindow
C:UIViewController初始化 loadView
, VC
的view
的nextResponser
會被設置爲VC
.
D:addSubView addSubView
操做過程當中,若是子subView不是VC的View,那麼subView
的nextResponser
會被設置爲superView
。若是是VC
的View
,那就是 subView -> subView.VC ->superView
若是在中途,subView.VC
被釋放,就會變成subView.nextResponser = superView
咱們使用一個現實場景來解釋這個問題:當一個用點擊屏幕上的一個按鈕,這個過程具體發生了什麼。
APP
檢測的那個端口。2.APP
啓動主線程RunLoop
會註冊一個端口事件,來檢測觸摸事件的發生。當事件到達,系統會喚起當前APP
主線程的RunLoop
。來源就是App主線程事件
,主線程會分析這個事件。
3.最後,系統判斷該次觸摸是否致使了一個新的事件, 也就是說是不是第一個手指開始觸碰,若是是,系統會先從響應網中 尋找響應鏈。若是不是,說明該事件是當前正在進行中的事件產生的一個Touch message
, 也就是說已經有保存好的響應鏈
二:事件傳遞鏈
經過兩種方法來作這個事情。
// 先判斷點是否在View內部,而後遍歷subViews
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
//判斷點是否在這個View內部
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; // default returns YES if point is in bounds
複製代碼
A: 流程
1:先判斷該層級是否可以響應(1.alpha>0.01 2.userInteractionEnabled == YES 3.hidden = NO)
2:判斷改點是否在view
內部,
3:若是在那麼遍歷子view
繼續返回可響應的view,直到沒有。
B:常見問題
父view設置爲不可點擊,子view能夠點擊嗎
不能夠,hit test 到父view就截止了
子view設置view不可點擊不影響父類點擊
同父view覆蓋不影響點擊
手勢對responder方法的影響
C:實際用法
點一一個圓形控件,如何實現只點擊圓形區域有效,重載pointInside
。此時可將外部的點也判斷爲內部的點,反之也能夠。
事件響應鏈在複雜功能界面進行不一樣控件間的通訊,簡便某些場景下優於代理和block
6:談談 KVC 以及 KVO 的理解?
7:
RunLoop
的做用是什麼?它的內部工做機制瞭解麼?
字面意思是「消息循環、運行循環」,runloop
內部實際上就是一個do-while循環
,它在循環監聽着各類事件源、消息,對他們進行管理並分發給線程來執行。
1.通知觀察者將要進入運行循環。 線程和 RunLoop 之間是一一對應的
2.通知觀察者將要處理計時器。
3.通知觀察者任何非基於端口的輸入源即將觸發。
4.觸發任何準備觸發的基於非端口的輸入源。
5.若是基於端口的輸入源準備就緒並等待觸發,請當即處理該事件。轉到第9步。
6.通知觀察者線程即將睡眠。
7.將線程置於睡眠狀態,直到發生如下事件之一:
8.通知觀察者線程被喚醒。
9.處理待處理事件。
10.通知觀察者運行循環已退出。
8:蘋果是如何實現
autoreleasepool
的?
arc下編譯器會優化成
void *context = objc_autoreleasePoolPush();
// {}中的代碼
objc_autoreleasePoolPop(context);
複製代碼
AutoreleasePoolPage
,中寫入須要自動釋放的對象,相似一種標記,調用objc_autoreleasePoolPop(context)
後,就會把這中間的對象release
一下。Thread Local Storage(TLS)
線程局部存儲,每次存入線程或者從線程取出來。{}
中的自動釋放對象,會在每一個runloop
結束時候去釋放,至關於一個大的autoreleasepool
中。9:談談你對
FRP (函數響應式)
的理解,延伸一下RxSwift
或者RAC
!
參考文章:RxSwift(1)— 初探 看這一篇文章也就夠了!而後結合 RxSwift
映射到 RAC
!函數響應式的思想是不變的!至於內部的封裝有所不一樣,可是最終倒是異曲同工!
10:平時開發有沒有玩過
Instrument
?
分析:這裏的內容很是有意思,對於一個iOS高級開發人員,我以爲還有頗有必要掌握的!尤爲開發3-5年,若是沒有掌握這些內容我以爲是不合格的
我我的建議在掌握面試題的同時還須要求職者更多的去分析和拓展!好比你的探索思路,你在這個知識點意外的延伸。還有你再實際開發過程的落地!而這些都是加分項!
1:什麼是 isa,isa 的做用是什麼?
2:一個實例對象的
isa
指向什麼?類對象指向什麼?元類isa 指向什麼?
isa
指向類isa
指向元類3:objc
中類方法和實例方法有什麼本質區別和聯繫?
類方法:
實例方法:
4:
load
和initialize
的區別?
+load
+load
方法會在當前類被加載到內存的時候調用, 有且僅會調用一次+load
方法時, 會先調用父類的+load
方法, 再調用子類的+load
方法+load
方法+load
方法時,不會調用父類的+load
方法+load
方法,+load
方法的調用順序,與Compile Sources
中出現的順序一致+initialize
initialize
方法在整個程序的運行過程當中只會被調用一次, 不管你使用多少次這個類都只會調用一次initialize
用於對某一個類進行一次性的初始化initialize
再調用子類的initialize
initialize
方法時,會把父類的實現繼承過來調用一遍,再次以前父類的initialize
方法會被優先調用一次Category
都實現了initialize
方法,會覆蓋類中的方法,只執行一個(會執行Compile Sources
列表中最後一個Category
的initialize
方法)5:
_objc_msgForward
函數是作什麼的?直接調用會發生什麼問題?
當對象沒有實現某個方法 ,會調用這個函數進行方法轉發。 (某方法對應的IMP
沒找到,會返回這個函數的IMP
去執行)
若是直接調用這個方法,就算實現了想調用的方法,也不會被調用,會直接走消息轉發步驟。
6:簡述下
Objective-C
中調用方法的過程
Objective-C
是動態語言,每一個方法在運行時會被動態轉爲消息發送,即:objc_msgSend(receiver, selector)
,整個過程介紹以下:objc
在向一個對象發送消息時,runtime
庫會根據對象的isa指針找到該對象實際所屬的類unrecognized selector sent to XXX
《何時會報unrecognized selector的異常》
中的說明PS:Runtime
鑄就了Objective-C
是動態語言的特性,使得C語言具有了面向對象的特性,在程序運行期建立,檢查,修改類、對象及其對應的方法,這些操做均可以使用runtime中的對應方法實現。
7:可否想向編譯後獲得的類中增長實例變量?可否向運行時建立的類中添加實例變量?爲何?
解釋:
runtime
中,類結構體中的objc_ivar_list
實例變量的鏈表和instance_size
實例變量的內存大小已經肯定, runtime
會調用 class_setvarlayout
或 class_setWeaklvarLayout
來處理 strong weak
引用.因此不能向存在的類中添加實例變量class_addIvar函數
.可是的在調用objc_allocateClassPair
以後, objc_registerClassPair
以前,緣由同上.8:談談你對切面編程的理解
維基百科對於切面編程(AOP)的解釋是這樣的:面向切面的程序設計(aspect-oriented programming,AOP
,又譯做面向側面的程序設計、觀點導向編程、剖面導向程序設計)是計算機科學中的一個術語,指一種程序設計範型。該範型以一種稱爲切面的語言構造爲基礎,切面是一種新的模塊化機制,用來描述分散在對象、類、函數)中的橫切關注點。參考文章
分析:
Runtime
這個模塊iOS面試不管初中高都會面試。我以爲這個模塊不光只是僅僅問問關於知識點內容,我更新想要聽到求職者在這裏面的爬坑探索辛歷路程!Runtime
這個模塊是刷開頁面開發的關鍵點!
1:HTTP的缺陷是什麼?
HTTP 主要有這些不足,例舉以下。
這些問題不只在HTTP
上出現,其餘未加密的協議中也會存在這類問題。
2:談談三次握手,四次揮手!爲何是三次握手,四次揮手?
參考文章 我以爲這個地方仍是須要自我理解,用本身的話去表達出來!
3:
socket
鏈接和Http
鏈接的區別
http
是基於 socket
之上的。socket
是一套完整的 tcp,udp
協議的接口。
HTTP協議
:簡單對象訪問協議,對應於應用層,HTTP
協議是基於TCP鏈接的。
TCP/IP是傳輸層協議
,主要解決數據如何在網絡中傳輸,而HTTP協議是應用層協議,主要解決如何包裝數據。
Socket是對TCP/IP 協議的封裝
,它自己不是協議,而是一個調用接口,經過Socket
,咱們才能使用TCP/IP協議
。
http鏈接
:就是所謂的短鏈接,即客戶端向服務器端發送一次請求,服務器端響應後鏈接即會斷掉。http
是客戶端用http
協議進行請求,發送請求時候須要封裝http
請求頭,並綁定請求的數據,服務器通常有web
服務器配合。http
請求方式爲客戶端主動發起請求,服務器才能給響應,一次請求完畢後則斷開鏈接以節省資源。服務器不能主動給客戶端響應。iPhone
主要使用的類是NSUrlConnection
。socket
是客戶端跟服務器直接使用socket「套接字」
進行拼接,並無規定鏈接後斷開,因此客戶端和服務器能夠保持鏈接,雙方均可以主動發送數據。通常在遊戲開發或者股票開發這種即時性很強的而且保持發送數據量比較大的場合使用。主要類是CFSocketRef。
4:HTTPS,安全層除了SSL還有,最新的? 參數握手時首先客戶端要發什麼額外參數
5:何時POP網絡,有了
Alamofire
封裝網絡URLSession
爲何還要用Moya
?
POP網絡
:面向協議編程的網絡可以大大下降耦合度!網絡層下沉,業務層上浮。中間利用 POP網絡
的Moya
隔開。若是你的項目是 RxSwift
函數響應式的也沒有關係!由於有 RxMoya
參考文章:
6:如何實現
dispatch_once
+ (instancetype)sharedInstance
{
/*定義相應類實例的靜態變量; 意義:函數內定義靜態變量,不管該函數被調用多少次, 在內存中只初始化一次,而且能保存最後一次賦的值 */
static ClassName *instance = nil;
/*定義一個dispatch_once_t(其實也就是整型)靜態變量, 意義:做爲標識下面dispatch_once的block是否已執行過。 static修飾會默認將其初始化爲0,當值爲0時纔會執行block。 當block執行完成,底層會將onceToken設置爲1,這也就是爲什 麼要傳onceToken的地址(static修飾的變量能夠經過地址修改 onceToken的值),同時底層會加鎖來保證這個方法是線程安全的 */
static dispatch_once_t onceToken;
/*只要當onceToken == 0時纔會執行block,不然直接返回靜態變量instance*/
dispatch_once(&onceToken, ^{
instance = [[ClassName alloc] init];
//...
});
return instance;
}
複製代碼
7:可否寫一個讀寫鎖?談談具體的分析 8:何時會出現死鎖?如何避免? 9:有哪幾種鎖?各自的原理?它們之間的區別是什麼?最好能夠結合使用場景來講
分析:這個模塊多是通常開發人員的盲區。對於這一塊必定要有本身的理解!學習的方向就是查漏補缺,一步一個吃掉!若是你一整塊去啃,你會發現很枯燥!雖然開發過程當中你可能用不到,可是面試這一塊是你必需要掌握的!
1.數據結構的存儲通常經常使用的有幾種?各有什麼特色?
數據的存儲結構是數據結構的一個重要內容。在計算機中,數據的存儲結構能夠採起以下四中方法來表現。
簡單的說,順序存儲方式就是在一塊連續的存儲區域 一個接着一個的存放數據。順序存儲方式把邏輯上相連的結點存儲在物理位置上相鄰的存儲單元裏,結點間的邏輯關係由存儲單元的鄰接掛安息來體現。順序存儲方式也稱爲順序存儲結構(sequentialstorage structure),通常採用數組或者結構數組來描述。 線性存儲方式主要用於線性邏輯結構的數據存放,而對於圖和樹等非線性邏輯結構則不適用。
連接存儲方式比較靈活,其不要求邏輯上相鄰的結點在物理位置上相鄰,結點間的邏輯關係由附加的引用字段表示。一個結點的引用字段每每指導下一個結點的存放位置。 連接存儲方式也稱爲連接式存儲結構(LinkedStorage Structure),通常在原數據項中增長應用類型來表示結點之間的位置關係。
索引存儲方式是採用附加索引表的方式來存儲結點信息的一種存儲方式。索引表由若干個索引項組成。索引存儲方式中索引項的通常形式爲:(關鍵字、地址)。其中,關鍵字是可以惟一標識一個結點的數據項。
索引存儲方式還能夠細分爲以下兩類:
稠密索引(Dense Index):這種方式中每一個結點在索引表中都有一個索引項。其中,索引項的地址指示結點所在的的存儲位置;
稀疏索引(Spare Index):這種方式中一組結點在索引表中只對應一個索引項。其中,索引項的地址指示一組結點的起始存儲位置。
散列存儲方式
散列存儲方式是根據結點的關鍵字直接計算出該結點的存儲地址的一種存儲的方式。 在實際應用中,每每須要根據具體數據結構來決定採用哪種存儲方式。同一邏輯結構採用不一樣額存儲方法,能夠獲得不一樣的存儲結構。並且這四種節本存儲方法,既能夠單獨使用,也能夠組合起來對數據結構進行存儲描述。
2.集合結構 線性結構 樹形結構 圖形結構 3.單向鏈表 雙向鏈表 循環鏈表 4.數組和鏈表區別 5.堆、棧和隊列
6.輸入一棵二叉樹的根結點,求該樹的深度?
若是一棵樹只有一個結點,它的深度爲1。 若是根結點只有左子樹而沒有右子樹, 那麼樹的深度應該是其左子樹的深度加1,一樣若是根結點只有右子樹而沒有左子樹,那麼樹的深度應該是其右子樹的深度加1. 若是既有右子樹又有左子樹, 那該樹的深度就是其左、右子樹深度的較大值再加1。
public static int treeDepth(BinaryTreeNode root) {
if (root == null) {
return 0;
}
int left = treeDepth(root.left);
int right = treeDepth(root.right);
return left > right ? (left + 1) : (right + 1);
}
複製代碼
7.輸入一課二叉樹的根結點,判斷該樹是否是平衡二叉樹?
1.時間複雜度
在計算機科學中,時間複雜性,又稱時間複雜度,算法的時間複雜度是一個函數,它定性描述該算法的運行時間。這是一個表明算法輸入值的字符串的長度的函數。時間複雜度經常使用大O符號表述,不包括這個函數的低階項和首項係數。使用這種方式時,時間複雜度可被稱爲是漸近的,亦即考察輸入值大小趨近無窮時的狀況。 時間複雜性
2.空間複雜度
空間複雜度(Space Complexity)是對一個算法在運行過程當中臨時佔用存儲空間大小的量度,記作S(n)=O(f(n))。好比直接插入排序的時間複雜度是O(n^2),空間複雜度是O(1) 。而通常的遞歸算法就要有O(n)的空間複雜度了,由於每次遞歸都要存儲返回信息。一個算法的優劣主要從算法的執行時間和所須要佔用的存儲空間兩個方面衡量。 時間複雜度&空間複雜度
3.經常使用的排序算法
4.字符串反轉
- (NSString *)reversalString:(NSString *)originString{
NSString *resultStr = @"";
for (NSInteger i = originString.length -1; i >= 0; i--) {
NSString *indexStr = [originString substringWithRange:NSMakeRange(i, 1)];
resultStr = [resultStr stringByAppendingString:indexStr];
}
return resultStr;
}
複製代碼
5.鏈表反轉(頭差法)
public Node reverseList(){
Node cur = head;
Node prev = null;
Node curNext = head.next;
Node reverHead = null;
while(cur!=null){
cur.next = prev;
cur = curNext;
prev = cur;
curNext = curNext.next;
}
reverHead = cur;
return reverHead;
}
> 6.有序數組合並
```objc
- (void)merge {
/* 有序數組A:一、四、五、八、10...1000000,有序數組B:二、三、六、七、9...999998,A、B兩個數組不相互重複,請合併成一個有序數組C,寫出代碼和時間複雜度。 */
//(1).
NSMutableArray *A = [NSMutableArray arrayWithObjects:@4,@5,@8,@10,@15, nil];
// NSMutableArray *B = [NSMutableArray arrayWithObjects:@2,@6,@7,@9,@11,@17,@18, nil];
NSMutableArray *B = [NSMutableArray arrayWithObjects:@2,@6,@7,@9,@11,@12,@13, nil];
NSMutableArray *C = [NSMutableArray array];
int count = (int)A.count+(int)B.count;
int index = 0;
for (int i = 0; i < count; i++) {
if (A[0]<B[0]) {
[C addObject:A[0]];
[A removeObject:A[0]];
}
else if (B[0]<A[0]) {
[C addObject:B[0]];
[B removeObject:B[0]];
}
if (A.count==0) {
[C addObjectsFromArray:B];
NSLog(@"C = %@",C);
index = i+1;
NSLog(@"index = %d",index);
return;
}
else if (B.count==0) {
[C addObjectsFromArray:A];
NSLog(@"C = %@",C);
index = i+1;
NSLog(@"index = %d",index);
return;
}
}
//(2).
//時間複雜度
//T(n) = O(f(n)):用"T(n)"表示,"O"爲數學符號,f(n)爲同數量級,通常是算法中頻度最大的語句頻度。
//時間複雜度:T(n) = O(index);
}
複製代碼
7.查找第一個只出現一次的字符(Hash查找)
兩個思路:
hash
�不一樣編譯器對字符數據的處理不同,因此hash以前先把字符類型轉成無符號類型;buffer數組
記錄當前只找到一次的字符,避免二次遍歷。# define SIZE 256
char GetChar(char str[])
{
if(!str)
return 0;
char* p = NULL;
unsigned count[SIZE] = {0};
char buffer[SIZE];
char* q = buffer;
for(p=str; *p!=0; p++)
{
if(++count[(unsigned char)*p] == 1)
*q++ = *p;
}
for (p=buffer; p<q; p++)
{
if(count[(unsigned char)*p] == 1)
return *p;
}
return 0;
}
複製代碼
8.查找兩個子視圖的共同父視圖
這個問的實際上是數據結構中的二叉樹,查找一個普通二叉樹中兩個節點最近的公共祖先問題 假設兩個視圖爲UIViewA
、UIViewC
,其中 UIViewA
繼承於UIViewB
,UIViewB
繼承於UIViewD
,UIViewC
也繼承於UIViewD
;即 A->B->D,C->D
- (void)viewDidLoad {
[super viewDidLoad];
Class commonClass1 = [self commonClass1:[ViewA class] andClass:[ViewC class]];
NSLog(@"%@",commonClass1);
// 輸出:2018-03-22 17:36:01.868966+0800 兩個UIView的最近公共父類[84288:2458900] ViewD
}
// 獲取全部父類
- (NSArray *)superClasses:(Class)class {
if (class == nil) {
return @[];
}
NSMutableArray *result = [NSMutableArray array];
while (class != nil) {
[result addObject:class];
class = [class superclass];
}
return [result copy];
}
- (Class)commonClass1:(Class)classA andClass:(Class)classB {
NSArray *arr1 = [self superClasses:classA];
NSArray *arr2 = [self superClasses:classB];
for (NSUInteger i = 0; i < arr1.count; ++i) {
Class targetClass = arr1[i];
for (NSUInteger j = 0; j < arr2.count; ++j) {
if (targetClass == arr2[j]) {
return targetClass;
}
}
}
return nil;
}
複製代碼
O(N^2)
一個改進的辦法:咱們將一個路徑中的全部點先放進NSSet中.由於NSSet的內部實現是一個hash表,因此查詢元素的時間的複雜度變成 O(1)
,咱們一共有N個節點,因此總時間複雜度優化到了O(N)
- (Class)commonClass2:(Class)classA andClass:(Class)classB{
NSArray *arr1 = [self superClasses:classA];
NSArray *arr2 = [self superClasses:classB];
NSSet *set = [NSSet setWithArray:arr2];
for (NSUInteger i =0; i<arr1.count; ++i) {
Class targetClass = arr1[i];
if ([set containsObject:targetClass]) {
return targetClass;
}
}
return nil;
}
複製代碼
9.無序數組中的中位數(快排思想)
10.給定一個整數數組和一個目標值,找出數組中和爲目標值的兩個數。
你能夠假設每一個輸入只對應一種答案,且一樣的元素不能被重複利用。 示例:給定nums = [2, 7, 11, 15], target = 9
--- 返回 [0, 1]
思路:
class Solution {
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] result = new int[2];
for(int i = 0; i < len; i++){
for(int j = i+1; j < len; j++){
if(nums[i] + nums[j] == target){
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
}
}
複製代碼
分析:這個模塊是絕大部分開發人員的軟肋!這個模塊是最能測試求職者思惟能力的!可是我不建議面試官直接讓求職者手寫 在那樣的面試緊張環境,手寫數據結構或者一些算法代碼,是很是有挑戰的!思惟到我以爲差很少!
1:設計模式是爲了解決什麼問題的?
設計模式(Design pattern)是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。
設計模式最主要解決的問題是經過封裝和隔離變化點來處理軟件的各類變化問題。 隔離變化的好處在於,將系統中常常變化的部分和穩定的部分隔離,有助於增長複用性,並下降系統耦合度。不少設計模式的意圖中都明顯地指出了其對問題的解決方案,學習設計模式的要點是發現其解決方案中封裝的變化點。
三本經典書籍:《GOF設計模式》,《設計模式解析》,《Head First Design Pattern》
設計模式是軟件開發領域的精髓之一。學好設計模式是目前每個開發人員的必修課,
2:看過哪些第三方框架的源碼,它們是怎麼設計的?
這個題目就看你我的的感觸,考量你平時的功底! 你們能夠針對性一些常見的框架:RxSwift
、Alamofire
、Moya
、AFNetworing
、YYKit
.... 掌握會用的同時,必需要掌握底層的核心思想!
3:能夠說幾個重構的技巧麼?你以爲重構適合何時來作?
在新功能增長時候,在擴展再也不簡單的時候。重構是一個不斷的過程。
4:開發中經常使用架構設計模式你怎麼選型?
這裏也是一道開放性題目!並非說某一種架構就是最優秀的~只有最合適的!根據公司狀況,項目現狀,以及開發者水平及時調整,設計!
5:你是如何組件化解耦的?
iOS 解藕
、組件化最經常使用的是使用統跳路由的方式,目前比較經常使用的 iOS 開源路由框架主要是JLRoutes
、MGJRouter
、HHRouter
等,這些路由框架各有優勢和缺點,基本能夠知足大部分需求。目前最經常使用來做路由跳轉,以實現基本的組件化開發,實現各模塊之間的解藕。可是,在實際中開發中會發現,沒法完全使用它們完成全部模塊間通訊,好比模塊間的同步、異步通訊等。再好比,咱們在配置了相關路由跳轉的 URL 後,如何在上線以後動態修改相關跳轉邏輯?在模塊間通訊時,如何在上線後動態修改相關參數?APP 可否實現相似 Web 的302跳轉
?學習參考
分析:架構設計這一層對於一個iOS中高級開發人員來講。這一塊那是他必需要去思考和感覺總結的!若是這位求職者開發4-5年了,一直都在作應用層界面開發,那麼想必他將來的職業晉升是已經落後了的!面試官不妨在這一個模塊單獨設計成一面,就和求職者一塊兒交流討論。畢竟這些思惟的設計,也許可以給面試官帶來一些不同的東西!😊
1:
tableView
有什麼好的性能優化方案?2: 界面卡頓和檢測你都是怎麼處理?
3:談談你對離屏渲染的理解?
4:如何下降APP包的大小
5:平常如何檢查內存泄露?
6:APP啓動時間應從哪些方面優化?
分析:如今APP性能優化已經成爲iOS中高級開發人員必需要去關係的東西!這一塊我我的建議結合實際開發去和求職者交流。而不是僅僅停留在知識點問答,由於沒有實際開發能力的性能優化都只是紙上談兵!
這一套面試題仍是有必定的水平和難度的!可是對於要應聘一份iOS中高級開發崗位,仍是比較中肯的!但願你們可以在接下來的跳槽漲薪有本身的思想。
文章有長,建議關注備份,無論是正在面試仍是即將面試,應該對你有幫助!既然看到這裏:麻煩點個贊吧!👍
PS:對本文內容存在疑問還望指出,謝謝!加油,靜候你的佳音