2018年2月iOS面試總結(jié)
今年2月中下旬因?yàn)閭€(gè)人原因,換了一份工作,期間面試了有4,5家,基本都是D輪或者上市公司,也從他們的面試筆試中看到了自己的一些不足,于是就想寫出來和大家分享一下,如果能幫到正在面試的同學(xué)更好。從面試題中,其實(shí)可以看到一些行業(yè)的發(fā)展,以及總體人才需求是怎樣的了。
一.筆試題
筆試基本都有一兩道基礎(chǔ)題,比如說UITableView的重用機(jī)制,ARC的基本原理,如何避免retain cycle,談?wù)剬?duì)MVC的理解,iOS內(nèi)存管理機(jī)制。這些大家應(yīng)該都很清楚了。筆試的內(nèi)容有幾種有選擇題,問答題,難一點(diǎn)的就是多選題了。我面試了一家就是給了10道多選題,多選,少選,錯(cuò)選都不行,當(dāng)時(shí)做完以后就感覺不是很好,有些題目題干就是一下哪些是對(duì)的,然后ABCD依次給4個(gè)不同的概念,這種一道題相當(dāng)于考了4個(gè)點(diǎn)??傊龅竭@種“惡心”的多選題也不要太慌,靜下心來一一甄別應(yīng)該能拿到不錯(cuò)的成績。
接下來我說幾個(gè)我當(dāng)時(shí)答的不怎么好的題目,我當(dāng)時(shí)記了一下,和大家分享一下。
1.進(jìn)程和線程的區(qū)別和聯(lián)系
這個(gè)其實(shí)是操作系統(tǒng)的問題,當(dāng)時(shí)一下子把我問的懵了,后來仔細(xì)回想了一下,加上自己的理解就答了,下面說說稍微完整的答案,大家可以準(zhǔn)備準(zhǔn)備,再問這種問題就可以完美作答了。
進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位. 線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.
一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程;同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行.
2.并行和并發(fā)的區(qū)別
并行是指兩個(gè)或者多個(gè)事件在同一時(shí)刻發(fā)生;
并發(fā)是指兩個(gè)或多個(gè)事件在同一時(shí)間間隔內(nèi)發(fā)生。
3.談?wù)勀銓?duì)Block和delegate的理解
我當(dāng)時(shí)是這么答的,delegate的回調(diào)更多的面向過程,而block則是面向結(jié)果的。如果你需要得到一條多步進(jìn)程的通知,你應(yīng)該使用delegation。而當(dāng)你只是希望得到你請(qǐng)求的信息(或者獲取信息時(shí)的錯(cuò)誤提示),你應(yīng)該使用block。(如果你結(jié)合之前的3個(gè)結(jié)論,你會(huì)發(fā)現(xiàn)delegate可以在所有事件中維持state,而多個(gè)獨(dú)立的block卻不能)
4.談?wù)刬nstancetype和id的異同
a、相同點(diǎn)
都可以作為方法的返回類型
b、不同點(diǎn)
①instancetype可以返回和方法所在類相同類型的對(duì)象,id只能返回未知類型的對(duì)象;②instancetype只能作為返回值,不能像id那樣作為參數(shù)
5.category中能不能使用聲明屬性?為什么?如果能,怎么實(shí)現(xiàn)?
這種問題一問,我當(dāng)時(shí)就感覺肯定能實(shí)現(xiàn)的,但是實(shí)在不知道怎么做,后來回來查了一下,才知道是用到了Runtime的知識(shí)了。貼一下答案
給分類(Category)添加屬性
利用Runtime實(shí)現(xiàn)getter/setter 方法
- @interface ClassName (CategoryName)@property (nonatomic, strong) NSString *str;@end//實(shí)現(xiàn)文件#import "ClassName + CategoryName.h"#importstatic void *strKey = &strKey;
- @implementation ClassName (CategoryName)
- -(void)setStr:(NSString *)str
- {
- objc_setAssociatedObject(self, & strKey, str, OBJC_ASSOCIATION_COPY);
- }
- -(NSString *)str
- {
- return objc_getAssociatedObject(self, &strKey);
- }
- @end
6.isKindOfClass和isMemberOfClass的區(qū)別
這個(gè)題目簡單,但是就是當(dāng)時(shí)緊張的情況下,別答反了。
isKindOfClass來確定一個(gè)對(duì)象是否是一個(gè)類的成員,或者是派生自該類的成員
isMemberOfClass只能確定一個(gè)對(duì)象是否是當(dāng)前類的成員
7.block里面的如何防止retain cycle
使用弱引用打斷block里面的retain cycle
MRC中 _block 是不會(huì)引起retain;但在ARC中 _block 則會(huì)引起retain。ARC中應(yīng)該使用 _weak或__unsafe_unretained弱引用
8.iOS多線程有哪幾種實(shí)現(xiàn)方法?GCD中有哪些隊(duì)列?分別是并行還是串行?
iOS中多線程編程工具主要3有:
- NSThread
- NSOperation
- GCD
dispatch queue分為下面3種:而系統(tǒng)默認(rèn)就有一串行隊(duì)列main_queue和并行隊(duì)列g(shù)lobal_queue:
GCD中有幾種隊(duì)列類型:
The main queue: 與主線程功能相同。實(shí)際上,提交至main queue的任務(wù)會(huì)在主線程中執(zhí)行。main queue可以調(diào)用dispatch_get_main_queue()來獲得。因?yàn)閙ain queue是與主線程相關(guān)的,所以這是一個(gè)串行隊(duì)列。
Global queues: 全局隊(duì)列是并發(fā)隊(duì)列,并由整個(gè)進(jìn)程共享。進(jìn)程中存在三個(gè)全局隊(duì)列:高、中(默認(rèn))、低三個(gè)優(yōu)先級(jí)隊(duì)列。可以調(diào)用dispatch_get_global_queue函數(shù)傳入優(yōu)先級(jí)來訪問隊(duì)列。
用戶隊(duì)列: 用戶隊(duì)列 (GCD并不這樣稱呼這種隊(duì)列, 但是沒有一個(gè)特定的名字來形容這種隊(duì)列,所以我們稱其為用戶隊(duì)列) 是用函數(shù) dispatch_queue_create
創(chuàng)建的隊(duì)列: 這些隊(duì)列是串行的。正因?yàn)槿绱耍鼈兛梢杂脕硗瓿赏綑C(jī)制, 有點(diǎn)像傳統(tǒng)線程中的mutex。
9.談?wù)刲oad和initialize的區(qū)別
這個(gè)題目當(dāng)時(shí)問出來,真的是一下子就傻了,平時(shí)雖然用的多,但是真的沒有注意比較過他們倆,看來平時(shí)學(xué)習(xí)還是多要問問所以然!
10.Core Data是數(shù)據(jù)庫么?有哪些重要的類?
我當(dāng)時(shí)一看問到是不是的問題,我就留神,感覺應(yīng)該不是常理的,當(dāng)時(shí)仔細(xì)想了想,Core Data確實(shí)不是一個(gè)數(shù)據(jù)庫,只是把表和OC對(duì)象進(jìn)行的映射,當(dāng)時(shí)并不是進(jìn)進(jìn)映射那么簡單,底層還是用的Sqlite3進(jìn)行存儲(chǔ)的,所以Core Data不是數(shù)據(jù)庫。
有以下6個(gè)重要的類:
(1)NSManagedObjectContext(被管理的數(shù)據(jù)上下文)
- 操作實(shí)際內(nèi)容(操作持久層)
作用:插入數(shù)據(jù),查詢數(shù)據(jù),刪除數(shù)據(jù)
(2)NSManagedObjectModel(被管理的數(shù)據(jù)模型)
- 數(shù)據(jù)庫所有表格或數(shù)據(jù)結(jié)構(gòu),包含各實(shí)體的定義信息
作用:添加實(shí)體的屬性,建立屬性之間的關(guān)系
操作方法:視圖編輯器,或代碼
(3)NSPersistentStoreCoordinator(持久化存儲(chǔ)助理)
- 相當(dāng)于數(shù)據(jù)庫的連接器
作用:設(shè)置數(shù)據(jù)存儲(chǔ)的名字,位置,存儲(chǔ)方式,和存儲(chǔ)時(shí)機(jī)
(4)NSManagedObject(被管理的數(shù)據(jù)記錄)
- 相當(dāng)于數(shù)據(jù)庫中的表格記錄
(5)NSFetchRequest(獲取數(shù)據(jù)的請(qǐng)求)
- 相當(dāng)于查詢語句
(6)NSEntityDescription(實(shí)體結(jié)構(gòu))
- 相當(dāng)于表格結(jié)構(gòu)
以上是我3月份面試遇到的問到的我一下子沒有答全或者沒答好的問題,大神全部都會(huì)的話請(qǐng)忽略哈。然后還有2個(gè)開放性的問題,那基本就是完全考驗(yàn)實(shí)力和自己理解的深度了。一個(gè)是談?wù)勀銓?duì)Runtime的理解,另一個(gè)是談?wù)勀銓?duì)Runloop的理解,由于我個(gè)人這兩個(gè)理解都不是很深,這里就不貼我的理解了。大家如果也感覺欠缺的,就趕緊去網(wǎng)上多看看吧!
11,sprintf,strcpy,memcpy使用上有什么要注意的地方

二.機(jī)試
這個(gè)環(huán)節(jié)基本都是大公司,或者是復(fù)試的時(shí)候會(huì)出現(xiàn),因?yàn)樯蠙C(jī)打代碼確實(shí)很很快區(qū)分出誰好誰壞,當(dāng)然我也面了一家這樣的公司,就給一張白紙,全程都是手寫代碼,這就完全是考驗(yàn)基本功了,因?yàn)闆]了代碼補(bǔ)全,沒有了編譯器告訴你哪里錯(cuò)了,一切都要靠自己的基本功來了。
機(jī)試基本就是靠靠算法題了。當(dāng)然也有算法題在筆試的最后幾道題出現(xiàn),那就看公司面試怎么安排的。
2年前我也是面試iOS,當(dāng)時(shí)對(duì)算法和 數(shù)據(jù)結(jié)構(gòu)要求很低的,很多面試基本都不問這些,今年面試多了這些問題,也讓我眼前一亮,也感嘆,2年技術(shù)發(fā)展之快,面試如今都會(huì)涉及到算法,不會(huì)算法和數(shù)據(jù)結(jié)構(gòu)的程序員的道路會(huì)越走越窄。
算法題,我遇到的都不難,畢竟不是BAT那種公司,簡單的就是直接要你寫一個(gè)算法出來,稍微高級(jí)點(diǎn)的就是有一個(gè)背景,然后要你解決問題,其實(shí)就是和ACM題目一樣的,不過就是沒有那么復(fù)雜。我貼幾段問的最多的算法,太難的題只能考自己的算法功底了。
二分查找 θ(logn)
遞歸方法
- int binarySearch1(int a[] , int low , int high , int findNum)
- {
- int mid = ( low + high ) / 2;
- if (low > high)
- return -1;
- else
- {
- if (a[mid] > findNum)
- return binarySearch1(a, low, mid - 1, findNum);
- else if (a[mid] < findNum)
- return binarySearch1(a, mid + 1, high, findNum);
- else
- return mid;
- }
- }
非遞歸方法
- int binarySearch2(int a[] , int low , int high , int findNum)
- {
- while (low <= high)
- {
- int mid = ( low + high) / 2; //此處一定要放在while里面
- if (a[mid] < findNum)
- low = mid + 1;
- else if (a[mid] > findNum)
- high = mid - 1;
- else
- return mid;
- }
- return -1;
- }
冒泡排序 θ(n^2)
- void bubble_sort(int a[], int n)
- {
- int i, j, temp;
- for (j = 0; j < n - 1; j++)
- for (i = 0; i < n - 1 - j; i++) //外層循環(huán)每循環(huán)一次就能確定出一個(gè)泡泡(最大或者最?。詢?nèi)層循環(huán)不用再計(jì)算已經(jīng)排好的部分
- {
- if(a[i] > a[i + 1])
- {
- temp = a[i];
- a[i] = a[i + 1];
- a[i + 1] = temp;
- }
- }
- }
快速排序 調(diào)用方法 quickSort(a,0,n); θ(nlogn)
- void quickSort (int a[] , int low , int high)
- {
- if (high < low + 2)
- return;
- int start = low;
- int end = high;
- int temp;
- while (start < end)
- {
- while ( ++start < high && a[start] <= a[low]);//找到第一個(gè)比a[low]數(shù)值大的位子start
- while ( --end > low && a[end] >= a[low]);//找到第一個(gè)比a[low]數(shù)值小的位子end
- //進(jìn)行到此,a[end] < a[low] < a[start],但是物理位置上還是low < start < end,因此接下來交換a[start]和a[end],于是[low,start]這個(gè)區(qū)間里面全部比a[low]小的,[end,hight]這個(gè)區(qū)間里面全部都是比a[low]大的
- if (start < end)
- {
- temp = a[start];
- a[start]=a[end];
- a[end]=temp;
- }
- //在GCC編譯器下,該寫法無法達(dá)到交換的目的,a[start] ^= a[end] ^= a[start] ^= a[end];編譯器的問題
- }
- //進(jìn)行到此,[low,end]區(qū)間里面的數(shù)都比a[low]小的,[end,higt]區(qū)間里面都是比a[low]大的,把a(bǔ)[low]放到中間即可
- //在GCC編譯器下,該寫法無法達(dá)到交換的目的,a[low] ^= a[end] ^= a[low] ^= a[end];編譯器的問題
- temp = a[low];
- a[low]=a[end];
- a[end]=temp;
- //現(xiàn)在就分成了3段了,由最初的a[low]樞紐分開的
- quickSort(a, low, end);
- quickSort(a, start, high);
- }
注釋我也寫上了,這些算法基本上簡單的算法題都能應(yīng)對(duì)了。
數(shù)據(jù)結(jié)構(gòu)的題目我就遇到了鏈表翻轉(zhuǎn),實(shí)現(xiàn)一個(gè)棧的結(jié)構(gòu),先進(jìn)后出的,樹先跟,中跟,后跟遍歷,圖的DFS和BFS。代碼就不貼了,太長了。如果有忘記的,可以再去翻翻回顧一下。
三.面試
面試基本都是問你之前做過什么項(xiàng)目啦,遇到了哪些問題了,自己如何解決的。談?wù)剬?duì)XXX的看法等等這些問題,只要平時(shí)認(rèn)真完成項(xiàng)目,其實(shí)面試反而問的東西更好答,因?yàn)槎际顷P(guān)于你項(xiàng)目的,這些你最了解和清楚了。
好了,到此就是2018年2月上海地區(qū)除了BAT公司,招聘iOS開發(fā)工程師的行情了,比2年前,最大的體會(huì)就是面試面更廣了,要求更高了。現(xiàn)在要求除了會(huì)OC,還要懂算法和數(shù)據(jù)結(jié)構(gòu),還有要么會(huì)ReactNative,或者PhoneGap一系列混合開發(fā)的框架,或者熟悉Swift,程序員要一直跟上主流才能不能被時(shí)代淘汰。才能具有競爭力。這也是我面試了這些公司的感悟,活到老學(xué)到老!最后希望大家都和我交流交流,我也是個(gè)iOS菜鳥,請(qǐng)大家多多指教!