iOS 中級面試題
半年前在知乎瀏覽到一個帖子,是關於如何面試iOS工程師。由於當時公司正在招聘iOS工程師,自己也面試了不少同學,就饒有興致的把自己的面試問題清單貼了出去,卻意外的引來了不少關注。還有不少同學認真回答並將答案私信於我交流的,還有求隱藏關卡的:(。由於工作太忙,私信和評論後面都沒怎麼回覆,這裡一併做下總結回覆:p
一份面試題的意義 — 我把收到的私信和一百多條評論都仔細讀了遍,發現大家之所以會關注大致出於以下幾個原因:
- 剛畢業的同學最近在找工作面試,想刷題增加面試通過率。
- 有一定的工作經歷的同學,想測試下自己的iOS水平,看自己能賣多少錢。
- 本身iOS基礎不錯,抱著技多不壓身心態補充知識的。
- 土豪老闆就差一個程式設計師了,想找份帶標準答案的面試題找真愛。
除了第三類同學心態正確外,其他的都高估面試題的作用了。面試題只是武功招式,知識體系才是內功心法。剛入門記住的都是招式,但招式何其多,面試的時候總會有遺漏和盲區,內功心法才是一通萬通,能以不變應萬變。這份面試題你答不全不能說明你iOS不及格,你全答對了你也不能上天。真正應該關注的是這份題背後所包含的理論知識體系。帖子裡還有其他不少優質回答,涵蓋候選人心態,習慣,基礎知識,產品理解等各個方面,都值得一讀。當然啦,既然出了題,就得有答案,就有它的目標群體。主要考察物件是從事iOS開發 1~3年的同學。不需要全部答對,能對一半以上問題侃侃而談就不錯了。
評論區百態
評論區有各路神仙吐槽,有的說難,有的說太容易,還有美工和安卓黨出現。大家七嘴八舌的討論意見很雜,但從中可以看出不少同學心態都不正確。技術這條路無窮無盡,廣度和深度的拓展都需要長年累月的積累,不存在什麼夠用就好了,用的時候再查下,沒必要了解這麼深。技術人員的視野和耐力決定在這條路上你能夠走多遠。下面幾類同學點名批評:
- 故作無知都機靈的。
- 覺得sqlite太重沒必要用的。
- 說太容易不願意答題的。
- 說都不會但不影響做專案的。
- 說圓角頭像讓美工切個圖就搞定的。
- 說一半不會沒必要深究的。
心態不及格。
合格的答案
出乎我意料之外的是有好幾位同學都正二八經的答了題,還把答案私信了我。這裡貼出其中一份答得還不錯的,再後面是答主自己的答案。 過關回答
我的答案
我有過不少面試和被面試的經歷,作為面試官出這份面試題從來就不是為了難倒面試者,而是為了多角度全面的瞭解面試者從而建立信任。面試的時候最擔心的是冷場,面試題只不過個引子,我心底裡最希望遇到的面試者是能夠舉一反三,除了回答問題本身之外,還能自信的旁徵博引,深談其背後原理或者相關的知識理論的。問題本身反而並不怎麼重要。這份清單裡的問題也並不難,這裡我列下我的回答以及從我的角度所期望的答案。
什麼是arc?(arc是為了解決什麼問題誕生的?)
現在有不少程式設計師是直接從arc上手的,從沒接觸過mrc,對arc的理解僅僅停留在apple幫助管理記憶體的層面。這個問題真正想了解的是對記憶體管理的理解,retain release雖然不用寫了,但arc下還是會有記憶體洩漏野指標crash的bug存在。如果能從retain count這種記憶體管理策略的角度去闡述arc誕生的意義就算答對了。如果還能扯下其他型別的策略,比如java裡的mark and sweep,那就加分點贊。
請解釋以下keywords的區別: assign vs weak, __block vs __weak
這道題屬於基礎語法題,可以網上搜到答案。不過真有不少同學不知道weak在物件釋放後會置為nil。__block關鍵字的理解稍微難點,因為在arc和mrc下含義(對retain count的影響)完全不同。理解了這幾個關鍵字就能應付使用block時引入retain cycle的風險了。這題還在記憶體管理的範疇之內。
使用atomic一定是執行緒安全的嗎?
看這題的問法不用想答案肯定是NO。有些人說不出所以然,有些人知道通過property的方式使用才能保證安全,還有人知道這個用來做多執行緒安全會有效能損耗,更有出色的候選人能談atomic,synchronized,NSLock,pthread mutex,OSSpinLock的差別。好奇寶寶點我。
描述一個你遇到過的retain cycle例子。(別撒謊,你肯定遇到過)
說沒遇到過的我很難相信你有過成熟專案的經歷。這題答不出了會扣很多很多分。用過block,寫過delegate的肯定都踩過坑。
+(void)load; +(void)initialize;有什麼用處?
這題屬於runtime範疇,我遇到過能說出對runtime的理解卻不知道這兩個方法的候選人。所以答不出來也沒關係,這屬於細節知識點,是加分項,能答出兩個message各在什麼階段接收就可以了。
為什麼其他語言裡叫函式呼叫, objective c裡則是給物件發訊息(或者談下對runtime的理解)
這題考查的是objective c這門語言的dynamic特性,需要對比c++這類傳統靜態方法呼叫才能理解。最好能說出一個物件收到message之後的完整的流程是如何的。對runtime有完整理解的候選人還能說出oc的物件模型。
什麼是method swizzling?
說了解runtime但沒聽過method swizzling是騙人的。這題很容易搜到答案。定位一些疑難雜症bug,hack老專案實現,閱讀第三方原始碼都有機會接觸到這個概念。
UIView和CALayer是啥關係?
能答出UIView是CALayer的delegate就及格了,能說出UIView主要處理事件,CALayer負責繪製就更好,再聊下二者在使用過程中對動畫流暢性影響的注意點就superb。UI流暢性是個大話題,推薦看下這兩篇文章。中餐,西餐。
如何高效能的給UIImageView加個圓角?(不準說layer.cornerRadius!)
這題討論的最多,還有說美工切圖就搞定的。答主在專案裡做過圓角頭像的處理,裡面的坑還真不少。cornerRadius會導致offscreen drawing有效能問題,美工切圖無法適用有背景圖的場景,即使加上shouldRasterize也有cache實效問題。正確的做法是切換到工作執行緒利用CoreGraphic API生成一個offscreen UIImage,再切換到main thread賦值給UIImageView。這裡還涉及到UIImageView複用,圓角頭像cache快取(不能每次都去繪製),新舊頭像替換等等邏輯。還有其他的實現方式,但思路離不開工作執行緒與主執行緒切換。
使用drawRect有什麼影響?(這個可深可淺,你至少得用過。。)
不少同學都用過drawRect或者看別人用過,但不知道這個api存在的含義。這不僅僅是另一種做UI的方式。drawRect會利用CPU生成offscreen bitmap,從而減輕GPU的繪製壓力,用這種方式最UI可以將動畫流暢性優化到極致,但缺點是繪製api複雜,offscreen cache增加記憶體開銷。UI動畫流暢性的優化主要平衡CPU和GPU的工作壓力。推薦一篇文章:西餐
ASIHttpRequest或者SDWebImage裡面給UIImageView載入圖片的邏輯是什麼樣的?(把UIImageView放到UITableViewCell裡面問更贊)
很多同學沒有讀原始碼的習慣,別人的輪子拿來只是用用卻不知道真正的營養都在原始碼裡面。這兩個經典的framework程式碼並不複雜,很值得一讀。能對一個UIImageView怎麼通過url展示一張圖片有完整的理解。涉及到的知識點也非常多,UITableViewCell的複用,memory cache, disk cache, 多執行緒切換,甚至http協議本身都需要有一定的涉及。
麻煩你設計個簡單的圖片記憶體快取器(移除策略是一定要說的)
記憶體快取是個通用話題,每個平臺都會涉及到。cache演算法會影響到整個app的表現。候選人最好能談下自己都瞭解哪些cache策略及各自的特點。常見的有FIFO,LRU,LRU-2,2Q等等。由於NSCache的快取策略不透明,一些app開發者會選擇自己做一套cache機制,其實並不難。
講講你用Instrument優化動畫效能的經歷吧(別問我什麼是Instrument)
Apple的instrument為開發者提供了各種template去優化app效能和定位問題。很多公司都在趕feature,並沒有充足的時間來做優化,導致不少開發者對instrument不怎麼熟悉。但這裡面其實涵蓋了非常完整的計算機基礎理論知識體系,memory,disk,network,thread,cpu,gpu等等,順藤摸瓜去學習,是一筆巨大的知識財富。動畫效能只是其中一個template,重點還是理解上面問題當中CPU GPU如何配合工作的知識。
loadView是幹嘛用的?
不要就簡單的告訴我沒用過,至少問下我有什麼用。。這裡是apple給開發者自己設定custom view的位置。說UI熟悉的一定要知道。
viewWillLayoutSubView你總是知道的。。
controller layout觸發的時候,開發者有機會去重新layout自己的各個subview。說UI熟悉的一定要知道。
GCD裡面有哪幾種Queue?你自己建立過序列queue嗎?背後的執行緒模型是什麼樣的?
兩種queue,序列和並行。main queue是序列,global queue是並行。有些開發者為了在工作執行緒序列的處理任務會自己建立一個serial queue。背後是蘋果維護的執行緒池,各種queue要用執行緒都是這個池子裡取的。GCD大家都用過,但很多關鍵的概念不少人都理解的模凌兩可。序列,並行,同步,非同步是GCD的核心概念。
用過coredata或者sqlite嗎?讀寫是分執行緒的嗎?遇到過死鎖沒?咋解決的?
沒用過sqlite是說不過去的。用過CoreData的肯定有很多血淚史要說。多謝執行緒模型你肯定做過比較選擇。死鎖是啥肯定也是要知道的,沒遇到過至少能舉個簡單的例子來說明。單個執行緒可以死鎖(main thread裡dispatch_sync到main queue),多個執行緒直接也可以死鎖(A,B執行緒互相持有對方需要的資源且互相等待)。
http的post和get啥區別?(區別挺多的,麻煩多說點)
這個可以說很多。不希望聽到的答案有
- 兩個差不多,隨便用一個。
- post比get安全(其實兩個都不安全)
能說下兩個http格式有什麼不同,各自應用的場景就合格了。更多可以閱讀下這個答案。
我知道你大學畢業過後就沒接觸過演算法資料結構了,但是請你一定告訴我什麼是Binary search tree? search的時間複雜度是多少?我很想知道!
很多人都很排斥資料結構和演算法題,我個人意見是複雜的可以不知道,基礎的一定要了解。時間複雜度是什麼得知道,list,queue,stack,table,tree這些都要明白是啥。連hash表的概念都不知道怎麼能保證在寫程式碼的時候注意效能呢。
隱藏關卡
其實當初寫這份答案的時候並沒有準備什麼隱藏關卡,只不過有一些從自己這些年專案經歷裡總結出來的有深度的知識點,感覺可以難倒不少同學:p。求隱藏關卡的同學真不少,近期我會再準備一份進階版面試題,權當作隱藏關卡。面向的物件是3~5年iOS開發經驗的同學。再次申明下:這只是一份面試題。
https://toutiao.io/posts/184340/app_preview