個人2020 八月iOS面試祕籍,爲你的跳槽保駕護航

前言

開門見山,這篇文章,適合「中高級iOS開發」,若是你如今待業,或者想跳槽而且還在求職的話,能夠看看本文,找一找靈感,但願對大家有幫助。html

2020年註定是一個特殊且不平凡的一年。*node

疫情之下,內憂外患,部分企業,倒下的倒下,扣薪的扣薪……,在這樣的大環境之下,便是危機也是機會,毅然決定踏上求職之路。ios

起初自信滿滿,在沒有作好充分準備狀況之下,簡歷寥寥草草,簡簡單單,以致於錯失很多好機會。切記切記!吃一塹長一智。面試

最後經過優化精簡排版簡歷,接到很多互聯網大廠的邀約面試。事實證實,擁有一份好簡歷,你已經成功一半了。最終,經過兩個月的艱苦奮戰,終於拿到本身比較滿意的offer。爲了作個總結,特開此篇,僅供參考~算法

個人感覺就是,本身一邊梳理知識點,一邊總結概括,收穫可能更大,因此打算把我梳理的部分分享出來,篇幅有點長,你們見諒。sql

覆蓋的點不是很全,分享給大家,但願大家在金九銀十的招聘季一切順利,offer收割機❤️❤️❤️編程

一、面試經歷

  座標:深圳,面試公司數:約15家, offer:到手的有2兩個,還有2家也進入談薪階段,談完後就一直沒下文了,表示很鬱悶。 面試方式:大部分採用遠程視頻面試,極少現場面試。面試特色:一輪iOS技術面(OC基礎+OC底層+算法), 二輪普遍技術面(網絡工程+數據結構+算法)+HR面。整體感覺,今年面試最大特色是,首先.機會比往年少不少,iOS招聘需求主要集中在3-5年工做經驗(換句話就是說崗位薪資20k廣泛是上限,固然大廠除外),其次. 技術方面:OC底層已經是必須掌握,Swift極少被提到。json

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

推薦閱讀

iOS開發——最新 BAT面試題合集(持續更新中)


二、iOS高頻(基礎+底層)面試題

1. 你在開發過程當中經常使用到哪些定時器,定時器時間會有偏差嗎,若是有,爲何會有偏差?

  iOS中常NSTimer、CADisplayLink、GCD定時器,其中NSTimer、CADisplayLink基於NSRunLoop實現,故存在偏差,GCD定時器只依賴系統內核,相對一前二者是比較準時的。數組

  偏差緣由是:與NSRunLoop機制有關, 由於RunLoop每跑完一次圈再去檢查當前累計時間是否已經達到定時設置的間隔時間,若是未達到,RunLoop將進入下一輪任務,待任務結束以後再去檢查當前累計時間,而此時的累計時間可能已經超過了定時器的間隔時間,故會存在偏差。

參考《iOS常見三種定時器-NSTimer、CADisplayLink、GCD定時器》

2. NSTimer、CADisplayLink會產生循環引用嗎?若是會,你是如何解決的?

  若是直接使用,會產生循環引用問題。能夠增長一箇中間類,給這個類添加一個用weak修飾的id 類型target屬性,並重寫中間類的消息轉發方法。實現以下代碼:

聲明文件.h:

#import <Foundation/Foundation.h>

@interface LXProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;

@end

實現文件.m

#import "LXProxy.h"

@interface LXProxy ()

/** weak target*/
@property (nonatomic, weak) id target;

@end

@implementation LXProxy

+ (instancetype)proxyWithTarget:(id)target{
LXProxy *proxy = [LXProxy alloc];
proxy.target = target;

return proxy;

}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
return [self.target methodSignatureForSelector:sel];

}

- (void)forwardInvocation:(NSInvocation *)invocation{
[invocation invokeWithTarget:self.target];

}

@end

調用代碼:

_timer = [NSTimer scheduledTimerWithTimeInterval:2 target:[LXProxy proxyWithTarget:self] selector:@selector(test) userInfo:nil repeats:YES];

3. 對Runtime有了解嗎,Runtime的方法查找過程是什麼樣的?有哪些實際應用?

  runtime是OC動態語言的運行時機制,OC的方法調用最後都轉成了runtime的objc_msgSend函數。

3.1 Runtime消息傳遞:

  1. 經過哈希算法,先從方法緩存中查找,若是命中,調用方法結束流程
  2. 若是緩存中沒有,則去當前類的方法列表中查找,若是命中,調用方法,加入當前方法緩存中,結束流程
  3. 若是當前類沒有對應方法,則去逐級父類方法列表中查找,若是命中,調用方法,加入當前方法緩存中,結束流程
    4.若是方法都不存在,進入方法動態解析,轉入消息轉發流程。

注:對於已經排序好的方法列表,採用二分查算法查找對應的執行函數,對應沒有排序的列表,採用通常遍歷方法查找對應執行函數。

3.2 消息轉發流程:

image.png

  1. 調用動態解析方法resolveClassMethod:(SEL)sel,若是動態添加方法(調用class_addMethod函數)並返回YES,則結束流程
  2. 若是上一步沒有實現動態添加方法,不管返回Yes仍是No,都會調用消息接受者重定向forwardingTargetForSelector方法,若是返回重定向接受者,則當前流程結束
  3. 若是返回上一步nil,則會調用methodSignatureForSelector獲取函數的參數和返回值類型,同時調用forwardInvocation消息通知當前對象。
  4. 若是上一步返回nil,消息沒法處理,App crash。

3.3 繼承關係:

e

  1. 實例對象(isntance)的isa指針指向類對象(class),類對象的存放實例方法(-方法)
  2. 類對象(class)的isa指針指向其元類對象(meta), 元類對象存放類方法(+方法)
  3. 根類對象(root class)的isa指針指向根元類對象(root meta),superclass指針指向nil.
  4. 根元類對象(root meta)的isa指針指向本身,superclass指針根類對象(root class)

由此可知, 實例方法(-方法)查找是沿着其superclass指針逐級父類查找,終於根類對象(root class)。而類方法(+方法)查找是沿着其superclass指針逐級父類(meta)查找,終於根類對象(root class),若是根類對象存在同名實例方法,則會調用同名實例方法

3.4 Runtime實際運用:

  1. 給NSTimer定時器聲明一箇中間類Proxy(消息轉發)
  2. 經過rumtime動態獲取類的全部屬性(json轉model、可歸檔類對屬性的歸檔及解歸檔操做)
  3. 反射機制(NSClassFromString, CTMediator原理)
  4. 交換系統方法(好比交換viewController生命週期方法,從而進行統一埋點等操做)
  5. 給分類添加屬性(經過關聯對象,實現getter, setter方法)

4. +load和+initlize調用時機?如今有一個類,給其添加了多個分類,而且每一個實現分類都實現了相同的類方法(好比+test),在調用這個方法時,會調用到哪一個分類?

  1. +initialize 方法,會在第一次初始化這個類以前被調用,咱們用它來初始化靜態變量。+load 方法會在加載類的時候就被調用,也就是 ios 應用啓動的時候,就會加載全部的類,就會調用每一個類的 +load 方法。initialize 方法相似一個懶加載,若是沒有使用這個類,那麼系統默認不會去調用這個方法,且默認只加載一次,且調用發生在 +init 方法以前。

  2. 調用最後參與編譯的分類的test方法。緣由:Xcode在編譯時根據buildPhases->Compile Sources裏面的從上至下順序編譯的,經過壓棧的方式將多個分類壓棧,且根據後進先出的原則,後編譯的會被先調用(插入頂部添加,即[methodLists insertObject:category_method atIndex:0]。因此objc_msgSend遍歷方法列表查找SEL 對應的IMP時,會先找到最後參與編譯的分類)當objc_msgSend找到方法並調用以後,結束傳遞消息,因此就造成了所謂的「覆蓋」。

5. App冷啓動優化?

 App冷啓動優化方案博客很是之多,歸納總結大體以下:

  1. pre-main優化:減小動態靜態庫,合併動態庫,移除廢棄第三方庫及所依賴的系統庫,二進制重排(抖音優化方案)
  2. runtime對類的註冊,類對象的初始化,load方法加載階段:精簡類,合併分類,移除廢棄分類等等
  3. main函數以後,推遲對三方庫註冊及延時調用耗時操做函數。能夠經過Instruments-->Time Profiler: 性能分析,定位耗時函數

6. UIView和CALayer有了解嗎,UI卡頓緣由是什麼,什麼是離屏渲染,爲何會產生離屏渲染,如何避免觸發離屏渲染?

  1. UIView和CALayer遵循單一職責原則,UIView負責事件處理,參與響應鏈,爲CALayer提供顯示的內容,CALayer負責內容顯示。
  2. UI卡頓緣由:參考

7. 事件響應響應鏈是什麼樣的?touchbegin,button touch,手勢的區別和聯繫?

8. 實際開發過程中,您使用到哪些設計模式?說說單例模式優缺點?蘋果設計的類對象是否是單例模式?

9. 實際開發過程中,您使用到哪些多線程,GCD與NSOperationQueue有什麼聯繫?

10. Runloop響應事件類型,經常使用幾種mode類型,與GCD有什麼聯繫?

11. 說說你對Block的理解,有幾種類型的Block, Block在捕獲自變量,局部靜態變量,全局變量,全局靜態變量有什麼區別, 什麼狀況下要注意Block循環引用問題?

12. NSString屬性,使用什麼關鍵字修飾,使用copy和strong修飾,有什麼區別?

13. 什麼是引用計數,說說你對自動釋放池的理解,它是何時釋放的,爲何用__weak修飾的變量所指向的對象在釋放時會自動把變量指針置爲nil?

三、網絡工程面試題

1. HTTPS和HTTP有什麼區別,HTTPS加密過程是什麼樣的,對稱加密和非對稱解密各有什麼優缺點?

HTTPS協議是由SSL/TLS+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全
HTTPS協議的主要做用能夠分爲兩種:一種是創建一個信息安全通道,來保證數據傳輸的安全;另外一種就是確認網站的真實性。
HTTP與HTTPS的區別,詳細介紹

2. TCP和UDP有什麼區別,TCP是可靠傳輸嗎,若是保證其可靠性?

2.1 TCP和UDP區別:

  1. TCP面向鏈接(如打電話要先撥號創建鏈接);UDP是無鏈接的,即發送數據以前不須要創建鏈接
  2. TCP提供可靠的服務。也就是說,經過TCP鏈接傳送的數據,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付
  3. TCP面向字節流,其實是TCP把數據當作一連串無結構的字節流;UDP是面向報文的UDP沒有擁塞控制,所以網絡出現擁塞不會使源主機的發送速率下降(對實時應用頗有用,如IP電話,實時視頻會議等)
  4. 每一條TCP鏈接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通訊
  5. TCP首部開銷20字節;UDP的首部開銷小,只有8個字節
  6. TCP的邏輯通訊信道是全雙工的可靠信道,UDP則是不可靠信道
    參考1

2.2 TCP可靠性:

  1. 校驗和
  2. 確認應答與序列號
  3. 超時重傳
  4. 鏈接管理
  5. 流量控制
  6. 擁塞控制(慢啓動,擁塞避免,快重傳,快恢復)
    參考2

3. 如何針對App弱網狀況優化

參考:淺談APP弱網優化

四、算法編程面試題

1. 判斷一個單向鏈表是否有環?

1.快慢雙指針法,快指針一次走兩步,慢指針一次走一步,若是有環必會相遇

public class ListNode {
     public var val: Int
     public var next: ListNode?
     public init(_ val: Int) {
         self.val = val
         self.next = nil
     }
 }

func validedCycleNoded(_ node: ListNode?) -> Bool {
    if node == nil {
        return false
    }

    var fast = node, slow = node

    while fast != nil {
        fast = fast?.next?.next
        slow = slow?.next

        if fast?.val == slow?.val {
            return true
        }
    }

    return false
}
  1. 可使用集合(Set)來判斷,來一次遍歷,把全部node添加到集合中,若是有重複,則確定要有環

2. 如何計算二叉樹的高度?

遞歸算法

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public var val: Int
 *     public var left: TreeNode?
 *     public var right: TreeNode?
 *     public init(_ val: Int) {
 *         self.val = val
 *         self.left = nil
 *         self.right = nil
 *     }
 * }
 */
class Solution {
    func maxDepth(_ root: TreeNode?) -> Int {
        guard let root = root else {return 0;}  
        return max(maxDepth(root.left), maxDepth(root.right)) + 1
    }
}

3. 合併兩個有序數組,同時去重

func mergeSortedArray(_ a: [Int], b:[Int]) ->[Int] {

    var i = 0
    var j = 0
    var ans = [Int]()

    //合併數組
    while i < a.count && j < b.count {
        if a[i] > b[j] {
            ans.append(b[j])
            j += 1
        }else if (a[i] == b[j]) {
            ans.append(b[j])
            j += 1
            i += 1
        }else {
            ans.append(a[i])
            i += 1
        }
    }

     //數組a有未合併元素
    while i < a.count {
        ans.append(a[i])
        i += 1
    }

    //數組b有未合併元素
    while j < b.count {
        ans.append(b[j])
        j += 1
    }

    return ans
}

4. 字符串編輯最短距離(LeeCode)

LeeCode-72.編輯距離
解法:動態規劃

5. 判斷括號的有效性(LeeCode)

LeeCode-20.有效的括號

class Solution {
    func isValid(_ s: String) -> Bool {
     if s.isEmpty {
        return true;
    }

    let map = ["}":"{", ")":"(","]":"["]
    var stack = [String]()

    for c in s {
       let key = String(c)
        if key == "{" || key == "(" ||  key == "[" {
            stack.append(key)
        } else if !stack.isEmpty && map[key] == stack.last {
            stack.removeLast()
        } else {
            return false
        }
    }

    return stack.isEmpty
    }

}
複製代碼

6. 25匹馬,現有5條跑道,沒有計時器,要找出最快3匹馬,至少要跑幾場?

至少跑7場,

  1. 對25匹馬隨機分紅5個組(A,B,C,D,E,F),每組跑一場,記錄每一匹馬在當前組中名次(第1名,第2名,第3名)(跑了五場)
  2. 從各個組中選取名次爲第一名的馬組成一組,跑一場,記錄名次(第六場),本組第1名則肯定了25匹馬中最快的一匹馬
  3. 選取第六場中名次爲第1名的所在原來組名次爲第二、3名馬,選取第六場中名次爲第2名的所在原來組名次第一、2名馬(它本身+第2名),選取第六場中名次爲第3名所在原來組名次第1名的馬(它本身),組成一組,跑一場,記錄名次(第七場),本場的第一、2名就是25匹馬中最快的第二、3名

7. 8瓶液體,其中1瓶有毒藥,毒藥1小時後至死,請問最快找出毒藥,須要幾隻老鼠?

1只老鼠能夠判定2瓶液體,2^3=8,因此須要3只老鼠便可,
對液體進行編號,001,010,011,100,101,110,111
給1號老鼠喂編碼個位數上是1的液體(001,011,101,111),
給2號老鼠喂編碼十位數上是1的液體(010,011,110,111),
給3號老鼠喂編碼百位數上是1的液體(100,101,110,111),
1小時後,
若是老鼠全活, 8號液體有毒,
若是全都死,7號液體有毒,
若是1號死,2,3活, 1號液體有毒
若是2號死, 1,3活,2號液體有毒
若是3號死,1,2活, 4號液體有毒
若是1,2號死,3活, 3號液體有毒
若是1,3號死,2活, 5號液體有毒
若是2,3號死,1活, 6號液體有毒

五、其餘面試題

1. 以下結構體,大小是多少?

struct  Node {
char a;
int b;
}  node;

結構體大小是8,考察結構體特性,內存對齊原則。

2. 定義一個全局變量a = 0; 開闢兩條子線程訪問 a = a + 1; 各for loop 10次,a的最終結果是多少?

<=20,線程安全問題。

3. 公司員工表(user)中有入職時間(t1)和離職時間(t2),請編寫sql語句,查詢18年3月(date1)-18年6月(date2)全部在職員工人信息

select * from user where 入職時間<201806 and (離職時間 is null or離職時間>201803)。

因爲時間關係,後面慢慢完善面試題答案。最後借用《三十而已》電視劇的臺詞做爲結尾:「以上就是我面試遇到的故事,未完待續~~~」

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

推薦閱讀

iOS開發——最新 BAT面試題合集(持續更新中)

做者:Xcode_boy
連接:https://juejin.im/post/6862898534857834510 來源:掘金

相關文章
相關標籤/搜索