iOS面試一些大公司的總結

無圖無封面

寫在前面

好久沒有在簡書寫東西了,之前還信誓旦旦承諾的一周一篇,最近幾個月一直都很忙,自從9月末從上家公司離職后,終于得了些空放松放松,10月1總會過去的,所以玩夠了的我,是時候開始正經找工作嘍~
因為目標比較堅定,就是要找一個大公司,所以投的簡歷也都很有目標性,下面我就總結一下這一周多對于一些大公司的面試情況吧~

自我介紹

程序員的自我介紹是我認為最糾結的了,因為我平時比較明騷,可到了正式場合就語無倫次了,所以這一塊我一般都只是簡單匯報一下我的背景信息、生辰八字啥的就得了...總之,我遇到的大公司都對這個一筆帶過,并沒有網上說的要多精辟才行。

簡歷

在聊面試經歷之前,先說說簡歷吧,我覺得一個人的簡歷寫的怎么樣直接影響到了面試的機會,畢竟簡歷這種東西第一個看的是不懂技術的HR大小姐。
一般iOS簡歷格式都差不多長一個樣:
教育背景
工作經驗
專業技能
項目經驗
自我評價
個人主頁
其中的專業技能和項目經驗用到的技術要點切記~~~
一定不要寫的太浮夸 !(自己不會的一定不要往上寫?。?/strong>
因為我發現,一般技術比較牛的面試官都會比較羞澀,他不一定會喜歡多看你,而是一個勁的盯著手里的那張簡歷看個不停,如果再遇到極度內斂性的技術宅,連自我介紹都可以省了,尷尬個半天才問一些你簡歷上面寫到的東西。
但是一些自己擅長或者理解的技術點一定要寫的高端簡潔一些!比如:
二次封裝AFN (無網絡走數據緩存)
AFN的封裝估計這個誰都寫了,不過在后面加一個點睛之筆,對于無網絡時的緩存機制,這個可就不一定都有了,面試官會一下子就被吸引住,接著問你怎么個緩存機制,這個時候暗自竊喜去吧,已經被你領上道了,早都準備好在這等你問呢~!

基礎題

一般大公司面試都不是一次性就能決定去留的,一般都要經歷三面甚至更多,所以一面的面試官如果沒讓你做題的話,就會先問一些基礎題來迅速過濾你是否值得下一步面試,因為這些基礎題面試官是一定會的(人家可以扯脖子跟你喊誰的對!),所以這些基礎題務必要準備的充分,可能直接影響到你的去留問題?。〗酉聛硎且恍┯龅降某柕膯栴}:
1、iOS屬性默認都有什么關鍵字?iOS9以后增加了什么關鍵字?
2、strong和copy的用法,strong是深拷貝嗎?對于字符串使用strong會有什么問題?對于可變數組使用copy這樣會有什么問題?
3、@synthesize和@dynamic是什么?用法?
4、代理是什么?協議/接口 模式應用場景?
5、block可以修改外部變量嗎?(為什么直接就可以修改全局變量?使用__block才可以修改局部變量?)
6、block分幾種類型?內存區域在什么位置?
7、實現響應鏈傳遞的兩個方法?(hitTest和pointInside)在哪些地方使用過?
這些基礎題我就不寫答案了,總之這些基礎題算是面試官對你的印象分吧,對于這些題大家一定要查一查,給它背下來,最好能理解下來,如果你能連續答對好幾道,一般面試官就直奔更深層的了,不確定對不對也沒關系,大膽的說出來,之后看面試官表情就知道對錯了,如果錯了,就不要糾結了趕緊說可能忘記了不過看一下API就能撿起來,迅速引導進入下一題,所以基礎這部分不要猶豫,會就會,不會就趕緊說可能忘記了,不要在那一個勁糾結。

底層

之后就是中級一點的題了,說一千道一萬,大公司和小公司面試就是不一樣,小公司會比較在乎你是否能勝任獨立開發啊,對于公司的app是否有困難啊,有幾年工作經驗啊,常用到哪些第三方庫啊之類的(真不是想黑小公司的意思)
而大公司的技術面試,還真的挺中規中矩,他們會比較關注你的一些對于一些常用的東西底層的理解,接下來我會列舉幾個被問到的底層問題:
1、KVO的底層實現原理,能否手動實現一個KVO,怎么處理?
2、block底層實際上是什么?block有幾種類型?block使用時的注意事項
3、OC對象本質是什么?
4、Runtime是什么?用到過runtime嗎?
5、SDWebImage底層實現?還有它的緩存機制?
6、AFNetWorking在成功回調后是處于什么線程之中?為什么會這樣?
這類的題,面試官可能會采用一種模擬場景的形式去問你,這樣你會感覺不是那么抽象,舉個遇到過的例子:
在多人合作開發環境下,可能會有重復添加KVO的時候,或者重復移除KVO的時候,重復添加或刪除KVO會怎么樣?采取什么方案去解決?

  • 這個問題其實就是看你解決問題的能力及思路,我覺得有兩種方法都可以實現,一種就是手動實現一個KVO,KVO本質是蘋果偷偷添加了一個派生類,將指針指向派生的子類,去監聽子類的set方法從而實現監聽的效果,手動實現一個KVO,并修改其添加和移除的方法,使用BOOL值作為屬性在方法內部進行判斷當前這個對象是否添加過或刪除過即可;第二種方法,就是寫一個類別,利用runtime去交換kvo的添加或移除方法到自定義的添加或移除方法,修改內部方法實現以達到該效果。

設計思想

一般面到這個時候,如果前兩部分都還可以的話,這部分就是給你訂價的時候了,面試官會調幾個業務需求讓你設計一種方案或者設計一個控件怎么封裝,其本質還是考察你的設計思想。

  • 在網易面試,被問到的問題:

如果讓你去設計SDWebImage的緩存機制,怎么去設計?

  • 我的回答:
    SDWebImage的緩存分為兩種,一種是內存緩存(MemoryCache),另一種是硬盤緩存(DiskCache),我會自定義一個單例緩存類,其中會有對應的兩種緩存作為屬性,另外還會暴露一些自定義屬性讓用戶可以去修改緩存的策略,例如最大緩存字節數,自動進行清理緩存還是不自動去清理等,還會暴露一些方法比如通過key去查找該緩存文件,當前key是否存在于沙盒或者內存中等。

  • 在另一家較大公司(名字不說了)被問到的問題:

如果一個自定義的Cell可能被用在多處,每處后臺返回的數據源模型(json原始數據)字段都是不同的,如果讓你去設計一種Model去兼容所有的業務需求,即不管原始數據什么樣都能一樣進行解析賦給Cell,你怎么去設計?

  • 我的回答:
    這個問題我覺得有很多種解決方法,我當時列舉了兩種,
    • 第一種是采用一個萬能Model,即設計一個只針對于View控件的Model,不去管數據源的模型??梢赃@么理解,這個Model中的所有字段都是針對于View的,而不是原始數據源的,這樣當你從AFN請求下來數據后需要再進行二次轉換,即將原始數據轉換成Model里的字段,這樣就不管你是什么原始數據最終都將轉換成只針對于View的Model里的字段,即萬能字段(這個想法說出之后,不知道為什么那個面試官楞了一下,可能沒理解還是我表達的不夠清楚,他最后想了想說這個也可以還有沒有更好的方法?我心中默念:mmp,難道只有你心里那個答案才是正確的么?)

    • 第二種解決方法是采用 協議/接口 模式,即在Cell中去創建一個代理人,代理人遵守Cell數據的接口,這個協議的所有方法即是賦給Cell數據的方法,當然也只考慮當前這個Cell,不考慮原始數據,不知道這么說能理解么?寫段代碼:

@protocol CustomCellGetModelProtocol <NSObject>

- (NSString *)getNameFromModel;

- (NSString *)getIconUrlFromModel;

- (NSString *)getGenderFromModel;

@end

@interface CustomTableViewCell : UITableViewCell

@property (nonatomic, strong) UILabel *nameLabel;

@property (nonatomic, strong) UIImageView *icon;

@property (nonatomic, strong) UILabel *genderLabel;

@property (nonatomic, weak) id<CustomCellGetModelProtocol> delegate;

- (void)reloadData;

@end

如上所示,這個CustomTableViewCell本身有一個代理對象遵從CustomCellGetModelProtocol協議去從原始數據中獲取該Cell所需要的數據,在內部通過reloadData去賦值(有人會問,為什么需要一個reloadData呢?)是這樣的,一般我們數據都是異步在網絡請求后成功回調才能得到,所以這個過程不可預知不知什么時候才能請求下來數據,因此控制器需要在網絡成功回調拿到數據后去刷新這個Cell,這是reloadData的用處之一,另一個作用就是如果業務需求是可能在同一個控制器中Cell變化數據很多次,那么這個時候可以根據reloadData方法去實現更新,下面放出內部實現:

- (void)reloadData {
    if (!self.delegate) return;
    if ([self.delegate respondsToSelector:@selector(getNameFromModel)]) {
        self.nameLabel.text = [self.delegate getNameFromModel];
    }
    if ([self.delegate respondsToSelector:@selector(getIconUrlFromModel)]) {
        [self.icon sd_setImageWithURL:[self.delegate getIconUrlFromModel]];
    }
    if ([self.delegate respondsToSelector:@selector(getGenderFromModel)]) {
        self.genderLabel.text = [self.delegate getGenderFromModel];
    }
}

數據結構和算法

當然如果你面的公司有需要或者是關于質量分析崗位的iOS(當然也有例外,前幾天去了一個小公司面試iOS,上來給了一份題,題上一共9道全是算法題。。。我直接轉身就走了),就會被問到數據結構和算法。
我反正這個是個大短板,因為我不是計算機出身,基礎不是那么好,對這塊只能后天去補,anyway,BAT公司基本都會問的,所以我們還是預防著好一些(網易是個例外,竟然沒被問到好開森,而且面的也不錯,期待網易的好消息),下面放傳送門:
了解數據結構和算法
所有算法

前幾天在百度的面試就被面試官無情的問到了:

  • 問:“算法你了解嗎?能列舉幾個常用的嗎?”
  • 答:“(常用?我尼瑪開發多少app了就特么沒用到過你跟我說常用?)嗯。。。了解過,比如什么冒泡排序、插入排序、希爾排序、快排!對,快速排序!”(因為我就會個快排,希望他問我快排)
  • 問:“快速排序的原理是什么?你可以用筆去表述”
  • 答:“(哈哈哈,上鉤了吧,老子就特么會一個快速排序)快排就是每次都通過比較前后大小先將一個中間量放置在它該有的位置,其余所有比它小的放在它左側,同理大的放右側,之后再進行遞歸左側和右側同樣采取這種方法直到所有數據都排序完成”
  • 問:“我們都知道快排平均次數是O(NlogN),那你知道快排的最壞情況的次數么?什么是最壞的情況?”
  • 答:“(哈哈,我尼瑪還真就不知道平均次數是多少,倒是記住了最壞的次數因為好記)知道,是O(N2二次方),最壞的情況可能是。。。(一通瞎說,感覺要黑)”
  • 問:“我們都知道每次排序一般都是從第一個數去比較后一個,如果恰好這個數是最大的時候會一直比較到頭,這樣的情況出現會比較慢,有沒有什么辦法優化一下速度”
  • 答:“(。。。快排還需要優化速度么?真是日了X)這個。。額。。(又是一通爛說)”

最后面試官終于放棄了對于快排的詢問,我剛放松了一下,他竟然又問了一個Google經典的面試題,雖然我當時沒聽過:

有一個100層的樓,你手里現在有兩個一模一樣的雞蛋,它們有可能都在一樓就摔碎,也可能從一百層樓摔下來沒事,要你用這兩個雞蛋確定哪一層是雞蛋可以安全落下的最高位置?

答案在這里,戳我菊花

我當時剛聽完我是懵逼的,因為百度那個面試官描述的不是很清楚,我又追問了一會,才明白到底是什么意思,首先我想到的是二分法,但他又說5分法是不更好一點?我思考了一會說“好像是哈”(心中一萬只草泥馬路過),他又問“那10分、100分呢?是不是越多越好呢?你從中有什么體會么?”說實話我是很懵逼的,以至于直接栽倒這個題了,然后他就沒有然后了,問我還有什么要問他的?我說沒了,就送我到前臺了,最后在送我的路上問我

  • “你知不知道你來面試的是什么崗位???”
  • “iOS啊”
  • “我知道是iOS,那是什么部門的你知道么?”
  • (我當時真不知道,因為HR把我推薦到別的部門了,過后查到才發現是什么質量分析評估啥的,那尼瑪不就該問算法么,好吧,栽就栽了,只能說和百度無緣了,對比百度其實我還是更喜歡網易的氣氛)

總之,百度面試的失利也對我挺有幫助,轉頭就去買了兩本關于算法、數據結構的書,有些時候如果默守陳規真不一定個好事,多出來面試走走會很迅速的發現自己哪方面不足,借此,希望大家都能及時找到自己的短板,最后放一些公司被問的很多的題及答案,供大家參考:

一些常見問題

1、__block 能修改外部變量根本原因是什么?
局部變量被__block修飾后將變量的內存地址從棧區移至堆區,所以block可不可以修改變量的根本原因是內存區的不同。詳情答案

2、自動釋放池中的變量什么時候釋放
自動釋放池其實會在其作用域結束時釋放池子,所有在池中的變量都會執行一次release操作,所以如果在池子中的變量執行過release操作后引用計數仍然大于0,那么就不會被釋放,反之為0就會被釋放,所以自動釋放池中的變量也不一定出了池作用域后就會被釋放的,詳情可以看:詳情答案

3、動態庫和靜態庫的區別
這個我說不清楚,看大神的解答吧 詳情答案

4、block根據內存區間分為幾種類型?
__NSMallocBlock /__NSStackBlock/ __ NSGlobalBlock
在ARC下,默認的block創建后都是GlobalBlock,當block內部引用到外部變量的值時,就會從GlobalBlock變到NSMallocBloc,注意即使你引用的是在棧區的局部變量也是NSMallocBloc,因為ARC下會將棧區的block copy到堆區,如果在MRC下需要手動去copy才會到堆區,所以關鍵在于block是否引用外部的變量,外部變量內存地址決定了block的內存地址,即NSStackBlock還是NSMallocBlock。
詳情答案

5、@dynamic與@synthesize的區別,使用場景?
dynamic告訴編譯器不要自動創建setter、getter方法,由用戶手動去實現,注意如果此時會找不到_(屬性名)的實例對象,只能self.(屬性名)。
synthesize如果你沒有手動實現setter方法和getter方法,那么在編譯的時候編譯器會自動為你加上這兩個方法。
如果沒有聲明,默認就是@synthesize 屬性名 = _屬性名;
使用場景:
synthesize 可以在需要同時實現set和get方法時聲明 ;修改實例對象的名稱等
dynamic 需要自己手動實現set和get方法時去聲明,注意一定要去實現,不然調用set或get時會導致程序崩潰
參考答案

10月18日陌陌面試更新:

6、當一個tableView上面加載很多Cell,但它們同時用SDWebImage去加載同一張網絡圖片(即URL相同),SD的底層會請求多次網絡請求嗎?如果不會,它是怎么做到同一張圖片下載完成后進行多次成功的回調并同時加載到Cell上呢?

說實話,SDWebImage緩存那塊源碼看的比較多,但下載這塊只是略過看了一下,我跟面試官說我這塊源碼沒看,他說沒關系按你自己的想法怎么去實現呢?
也是出于沒自信,先后說了兩個方法,其中一個還真被我猜中了,但面試官沒有表現出來我對的意思。

第一種:采用通知中心,這個問題就很簡單了,對于同一張圖片URL作為key值,在sd_setImageWithURL:(NSURL *)url forState:(UIControlState)state這步時,就已經添加好通知并將該URL作為判斷依據存入隊列數組,判斷當前下載隊列數組里有無這個URL,如果沒有執行正式的異步下載,若有表明已經在下載當中,執行等待,即return,當第一個網絡請求下載好后發送關于該URL的通知告訴其余的下載隊列這個已經下載完畢并將最終的UIImage作為參數回調,其他去執行UI操作即可。

第二種:利用block進行回調,對于每一個下載隊列都需要知道當前的圖片下載進度和下載完成的狀態,即需要兩個block(progressBlock、completeBlock),將每一個隊列包含的block都存入數組,然后在執行下載之前還是先檢查是否是第一次下載,如果是就直接進入下載隊列,否則不走回調,等待第一個下載隊列下載圖片的完成,當下載完成時,通過URL找到存儲的block數組進行回調,這樣就實現了只執行一次下載任務完成多次回調。

好吧,讓我們來check out一下源碼,看看它到底是怎樣實現的?
sd_setImage底層有一個這樣的方法downloadImageWithURL:options:progress:completed:,在該方法內部會根據addProgressCallback:completedBlock:forURL:createCallback:這個方法的回調進行最終的下載任務,那么只要在這個方法里去處理是否進入下載即可,以下是該方法的實現,讓我們來分析:

- (void)addProgressCallback:(SDWebImageDownloaderProgressBlock)progressBlock completedBlock:(SDWebImageDownloaderCompletedBlock)completedBlock forURL:(NSURL *)url createCallback:(SDWebImageNoParamsBlock)createCallback {
    // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data.
    if (url == nil) {
        if (completedBlock != nil) {
            completedBlock(nil, nil, nil, NO);
        }
        return;
    }

    dispatch_barrier_sync(self.barrierQueue, ^{
        BOOL first = NO;
        if (!self.URLCallbacks[url]) {
            self.URLCallbacks[url] = [NSMutableArray new];
            first = YES;
        }

        NSMutableArray *callbacksForURL = self.URLCallbacks[url];
        NSMutableDictionary *callbacks = [NSMutableDictionary new];
        if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy];
        if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy];
        [callbacksForURL addObject:callbacks];
        self.URLCallbacks[url] = callbacksForURL;

        if (first) {
            createCallback();
        }
    });
}

先用GCD同步執行等待確保前面任務都執行完,注意URLCallbacks這個屬性是一個字典,存儲在SDWebImageDownloader單例中,圖片的url作為key,由于同一張圖片可能在多處加載,所以callbackBlock可能會有很多,也驗證了我第二個思路,這里用的Array用來存儲(即[callbacksForURL addObject:callbacks];用來添加每一個隊列里的回調block),在這段代碼的最后可以看到,用一個first局部變量表示是否是第一次下載

       if (!self.URLCallbacks[url]) {
            self.URLCallbacks[url] = [NSMutableArray new];
            first = YES;
        }

如果是則回調completedBlock告訴管理器這是第一次對于該URL的下載,你可以開始下載了。

       if (first) {
            createCallback();
        }

雖然在二面的時候被拒了,面試官說我基礎知識不牢固。雖無緣陌陌,但這次的面試經歷讓我又找到了些自己的不足(有些說對了,又因為不自信改了答案)

10.19日晚更新

Bad News
網易給答復說最終沒有錄用我 很遺憾 無緣網易
心情有一點小失落 又得繼續開始找工作了 好吧 相信屬于我的那個公司還在等我 千萬不要氣餒 以此鼓勵自己

[圖片上傳失敗...(image-3520aa-1513048180203)]

寫在后面

接下來面試我會隨時進行補充,希望還在找工作的朋友們,大家都能夠做到從容不迫找到心中理想的公司。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,200評論 30 471
  • 1.1 談一談GCD和NSOperation的區別? 首先二者都是多線程相關的概念,當然在使用中也是根據不同情境進...
    John_LS閱讀 1,323評論 0 12
  • 2016.05.20 10:24 塵封已久的學習基礎總結,最近公司項目不是很忙,終于抽空整理出來,現分享出來。 1...
    si1ence閱讀 19,754評論 61 589
  • 作者si1ence2016.05.20 10:24* http://www.lxweimin.com/p/bc3f8...
    Kiddz閱讀 1,220評論 0 12
  • 上班真累,一天到晚都不能坐一下!真想好好的歇個年假,可能由于過年的活躍期還沒有消失的原因吧!現在覺得做老師的真好,...
    OO碰到OO閱讀 218評論 0 0