本文將回答知乎上iOS面試問題鏈接:如何面試 iOS 工程師?
Model層:
數(shù)據(jù)持久化存儲(chǔ)方案有哪些?沙盒的目錄結(jié)構(gòu)是怎樣的?各自一般用于什么場(chǎng)合?SQL語句問題:inner join、left join、right join的區(qū)別是什么?sqlite的優(yōu)化網(wǎng)絡(luò)通信用過哪些方式(100%的人說了AFNetworking...)如何處理多個(gè)網(wǎng)絡(luò)請(qǐng)求并發(fā)的情況
在網(wǎng)絡(luò)請(qǐng)求中如何提高性能
在網(wǎng)絡(luò)請(qǐng)求中如何保證安全性
語言與基礎(chǔ)知識(shí):
內(nèi)存中的棧和堆的區(qū)別是什么?那些數(shù)據(jù)在棧上,哪些在堆上?#define和const定義的變量,有什么區(qū)別什么情況下會(huì)出現(xiàn)內(nèi)存的循環(huán)引用block中的weak self,是任何時(shí)候都需要加的么?GCD的queue,main queue中執(zhí)行的代碼,一定是在main thread么?
NSOperationQueue有哪些使用方式
NSThread中的Runloop的作用,如何使用?
.h文件中的變量,外部可以直接訪問么?(注意是變量,不是property)講述一下runtime的概念,message send如果尋找不到相應(yīng)的對(duì)象,會(huì)如何進(jìn)行后續(xù)處理 ?TCP和UDP的區(qū)別是什么?
MD5和Base64的區(qū)別是什么,各自場(chǎng)景是什么?
二叉搜索樹的概念,時(shí)間復(fù)雜度多少?
架構(gòu):(我們招的不是架構(gòu)師,這方面問的不多,而且從之前對(duì)APP的架構(gòu)介紹里可以邊聽邊問)
哪些類不適合使用單例模式?即使他們?cè)谥芷谥兄粫?huì)出現(xiàn)一次。
Notification的使用場(chǎng)景是什么?同步還是異步?
簡單介紹一下KVC和KVO,他們都可以應(yīng)用在哪些場(chǎng)景?
APP相關(guān):
如何添加一個(gè)自定義字體到工程中
如何制作一個(gè)靜態(tài)庫/動(dòng)態(tài)庫,他們的區(qū)別是什么?
Configuration中,debug和release的區(qū)別是什么?
簡單介紹下發(fā)送系統(tǒng)消息的機(jī)制(APNS) UI:
系統(tǒng)如何尋找到需要響應(yīng)用戶操作的那個(gè)Responder
多屏幕尺寸的適配
UIButton的父類是什么?UILabel呢?
push view controller 和 present view controller的區(qū)別
描述下tableview cell的重用機(jī)制
UIView的frame和bounds的區(qū)別是什么
最后是幾道場(chǎng)景題,也是我最喜歡問的:
發(fā)送10個(gè)網(wǎng)絡(luò)請(qǐng)求,然后再接收到所有回應(yīng)之后執(zhí)行后續(xù)操作,如何實(shí)現(xiàn)?
實(shí)現(xiàn)一個(gè)第三方控件,可以在任何時(shí)候出現(xiàn)在APP界面最上層
實(shí)現(xiàn)一個(gè)最簡單的點(diǎn)擊拖拽功能。上面那個(gè)拖拽之外,如果在手放開時(shí),需要根據(jù)速度往前滑動(dòng)呢?
如何減小一個(gè)應(yīng)用程序的尺寸?
如何提高一個(gè)性用程序的性能?
不同版本的APP,數(shù)據(jù)庫結(jié)構(gòu)變化了,如何處理?
作者:張之誠
鏈接:https://www.zhihu.com/question/19604641/answer/56306604
來源:知乎
下面是給出的答案,有不對(duì)的地方還請(qǐng)多多指教!
一. 數(shù)據(jù)持久化存儲(chǔ)方案有哪些?
- 屬性列表(NSUserdefaults)
NSUserdefaults適合存儲(chǔ)輕量級(jí),弱業(yè)務(wù)相關(guān)的數(shù)據(jù),存儲(chǔ)在應(yīng)用程序的一個(gè)plist文件里,Document目錄平級(jí)的/Library/Prefereces里。- NSCoding
- 文件存儲(chǔ)(NSFileManager)
- NSKeydeArchive歸檔存儲(chǔ)
又名序列化,把對(duì)象轉(zhuǎn)為字節(jié)碼,通過key-value以文件的形式加密存儲(chǔ)在磁盤上- 數(shù)據(jù)庫
SQlite庫提供了三種方式:Single Thread, Multi Thread, Serialized(默認(rèn))
Serialized串行隊(duì)列執(zhí)行所有操作,- Keychain
蘋果提供的帶有可逆加密的存儲(chǔ)機(jī)制,存儲(chǔ)密碼和用戶唯一標(biāo)識(shí)串。
二. 沙盒的目錄結(jié)構(gòu)是怎樣的?各自一般用于什么場(chǎng)合?
在應(yīng)用的安裝過程中,系統(tǒng)為每個(gè)單獨(dú)的應(yīng)用程序生成它的主目錄和一些關(guān)鍵的子目錄。蘋果對(duì)沙盒的幾天限制:
- 應(yīng)用程序在自己的沙盒中運(yùn)作,不能訪問任何其他應(yīng)用程序的沙盒;
- 應(yīng)用之間不能共享數(shù)據(jù);
- 蘋果禁止任何讀寫沙盒以外的文件,禁止應(yīng)用程序?qū)?nèi)容寫到沙盒以外的文件中;
- 沙盒目錄里有三個(gè)文件夾:Documents、Library、Temp、AppName.app目錄
Documents-----存儲(chǔ);應(yīng)用程序的數(shù)據(jù)文件,存儲(chǔ)用戶數(shù)據(jù)或其他定期備份的信息;
library下有兩個(gè)文件夾:Caches存儲(chǔ)應(yīng)用程序再次啟動(dòng)所需的信息,
Preferences包含應(yīng)用程序的偏好設(shè)置文件,不可在這更改偏好設(shè)置;
temp存儲(chǔ)臨時(shí)文件- 獲取沙盒根目錄方法:NSHomeDirectory獲取
獲取Document路徑
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).
三. SQL語句問題:inner join、left join、right join的區(qū)別是什么?
left join(左聯(lián)接)返回包括左表中的所有記錄和右表中聯(lián)結(jié)字段相等的記錄
right join(右聯(lián)接)返回包含右表中的所有記錄和左表中聯(lián)接字段相等的記錄
inner join (等值聯(lián)接) 只返回兩個(gè)表中聯(lián)接字段相等的行
select *from A left join B on A.id = B.id
四. 在網(wǎng)絡(luò)請(qǐng)求中如何提高性能?
1.減少請(qǐng)求寬帶:(壓縮請(qǐng)求與響應(yīng))
(1)使用JSON數(shù)據(jù),高效的數(shù)據(jù)交換格式
(2)Base64格式上傳文件,對(duì)Base64數(shù)據(jù)進(jìn)行壓縮,減少30%的數(shù)據(jù)體積
2.降低請(qǐng)求延遲:(管道化請(qǐng)求)
(1)降低多個(gè)請(qǐng)求的延遲
(2)在單個(gè)TCP連接上發(fā)送HTTP請(qǐng)求,以管道的形式發(fā)送HTTP請(qǐng)求,從而優(yōu)化全雙工TCP連接的使用。
(3)Apache和IIS都支持管道,無需任何額外的配置。
3.避免網(wǎng)絡(luò)請(qǐng)求
(1)在本地緩存內(nèi)容避免不必要的網(wǎng)絡(luò)流量
五. 在網(wǎng)絡(luò)請(qǐng)求中如何保證安全性
https 和 加密
六. 內(nèi)存中的棧和堆的區(qū)別是什么?那些數(shù)據(jù)在棧上,哪些在堆上?
棧區(qū)是由編譯器自動(dòng)分配釋放,存放方法(函數(shù))的參數(shù)值,局部變量的值等,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存區(qū)域。棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的。
堆由程序員分配釋放,若不釋放,程序結(jié)束時(shí)由OS回收,向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域,
OC對(duì)象放在堆內(nèi),非OC對(duì)象一般放在棧里面
棧是吃了吐,堆是吃了拉
鏈接:iOS 堆和棧的區(qū)別?
七. #define和const定義的變量,有什么區(qū)別:
1.#define在預(yù)處理階段進(jìn)行簡單的替換,const在編譯階段使用;
2.#define不做類型檢查,只是簡單的替換,const有數(shù)據(jù)類型會(huì)執(zhí)
行類型檢查;
3.#define不能調(diào)試, const可以調(diào)試
4.#define大量的宏造成編譯時(shí)間久
5.#define可以定義一些簡單的函數(shù),const不可以
6.const修飾右邊的變量只讀 NSString * const p
static作用:
- 修飾局部變量
(1)延長局部變量的生命周期,程序結(jié)束才會(huì)銷毀
(2)局部變量只會(huì)生成一份內(nèi)存,只會(huì)初始化一次- 修飾全局變量:只能在本文件中訪問,修改全局變量的作用域,生命周期不會(huì)改
extern作用:聲明全局變量
聲明一個(gè)變量,不能定義變量
static和const聯(lián)合使用:聲明一個(gè)靜態(tài)全局只讀變量
static NSString * const name = @"name";
extern與const聯(lián)合使用
當(dāng)有多個(gè)文件使用同一個(gè)字符串常量時(shí),可以使用extern和const組合
新建一個(gè)全局的文件管理全局的變量
在.m里定義 NSString *const YYTextViedBegin = @"YYTextVditing";
在.h里應(yīng)用 UIKIT_EXTERN NSString *const YYTextViewTextDidBegin;
八. 什么情況下會(huì)出現(xiàn)內(nèi)存的循環(huán)引用
block,A強(qiáng)引用了block,block有強(qiáng)引用了A
九. block中的weak self,是任何時(shí)候都需要加的么?
只有產(chǎn)生循環(huán)引用了才會(huì)加
十. GCD的queue,main queue中執(zhí)行的代碼,一定是在main thread么?
對(duì)于queue中所執(zhí)行的代碼不一定在main thread中。如果
queue是在主線程中創(chuàng)建的,那么所執(zhí)行的代碼就是在主線程中執(zhí)行。如果是在子線程中創(chuàng)建的,那么就不會(huì)在main thread中執(zhí)行。
對(duì)于main queue就是在主線程中的,因此一定會(huì)在主線程中執(zhí)行。獲取 main queue就可以了,不需要我們創(chuàng)建,獲取方式通過調(diào)用方法 dispatchgetmain_queue來獲取。
鏈接:多線程
十一. NSOperationQueue有哪些使用方式
與GCD的區(qū)別
- GCD使用方便,代碼邏輯清晰,
- GCD是C語言構(gòu)成的API,NSOperationQueue是基于GCD的Objective-C對(duì)象的封裝,提供了更多的選擇
- NSOperationQueue任務(wù)可以很方便的取消未執(zhí)行的任務(wù)
- GCD只支持FIFO隊(duì)列,NSOperation可以通過依賴關(guān)系設(shè)置操作執(zhí)行順序,控制在特定的任務(wù)執(zhí)行完后才執(zhí)行,GCD可以通過barrier或者group控制執(zhí)行順序,但是依賴關(guān)系復(fù)雜時(shí),代碼邏輯太復(fù)雜
- NSOperation支持KVO監(jiān)聽任務(wù)的狀態(tài)(完成、執(zhí)行中、取消等狀態(tài))
- NSOperation可以設(shè)置同一隊(duì)列中任務(wù)的優(yōu)先級(jí),GCD只能區(qū)分不同隊(duì)列的優(yōu)先級(jí)
- 自定義NSOperation,封裝任務(wù)邏輯,提高整個(gè)代碼的復(fù)用度
十二. NSThread中的Runloop的作用,如何使用
runloop是一個(gè)線程里運(yùn)行循環(huán),并對(duì)收到的事件進(jìn)行處理,
- 保持線程長時(shí)間存活
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
[runLoop run];- 用于定時(shí)器
十三. .h文件中的變量,外部可以直接訪問么?(注意是變量,不是property)
成員變量三中權(quán)限:@private, @protected, @public
不可以,.h中的成員變量默認(rèn)是@protected權(quán)限,子類可以訪問,可以做權(quán)限修改,外部調(diào)用會(huì)報(bào)protected錯(cuò)誤
十四. 講述一下runtime的概念,message send如果尋找不到相應(yīng)的對(duì)象,會(huì)如何進(jìn)行后續(xù)處理 ?
objc向一個(gè)對(duì)象發(fā)送消息,runtime會(huì)根據(jù)對(duì)象的isa指針找到該對(duì)象實(shí)際所屬類,然后在該類方法列表以及父類的方法列表中查找方法實(shí)現(xiàn),如果向一個(gè)nil對(duì)象發(fā)送消息,在查找isa指針時(shí)就是0地址返回,不會(huì)出錯(cuò)
十五. TCP和UDP的區(qū)別是什么?
TCP:面向連接、傳輸可靠(保證數(shù)據(jù)正確性,數(shù)據(jù)順序)、用于傳輸大量數(shù)據(jù)(流模式)、速度慢、建立連接需要開銷較多(時(shí)間,系統(tǒng)資源)。
UDP:面向非連接、傳輸不可靠、用于傳輸少量數(shù)據(jù)(數(shù)據(jù)包模式)、速度快。
TCP在連接持續(xù)過程中,socket收到的數(shù)據(jù)是同一臺(tái)主機(jī)發(fā)出。
UDP只要知道接收端的IP和端口,網(wǎng)絡(luò)可達(dá),任何主機(jī)都可以向接受端發(fā)送數(shù)據(jù)
十六. MD5和Base64的區(qū)別是什么,各自場(chǎng)景是什么
MD5是用哈希算法(摘要算法)加密的:不可逆;密文總是16進(jìn)制32位
一般用于文件校驗(yàn)、密碼存儲(chǔ)
Base64是公開的代碼加密,url加密
十七. 二叉搜索樹的概念,時(shí)間復(fù)雜度多少
采用二叉樹鏈表作為存儲(chǔ)結(jié)構(gòu),每個(gè)左節(jié)點(diǎn)均小于父節(jié)點(diǎn),每個(gè)右節(jié)點(diǎn)均大于父節(jié)點(diǎn)
時(shí)間復(fù)雜度:O(log2(n))
十八. 哪些類不適合使用單例模式?即使他們?cè)谥芷谥兄粫?huì)出現(xiàn)一次。
同一類型的對(duì)象需要在不同的用例場(chǎng)景發(fā)生變化
十九. Notification的使用場(chǎng)景是什么?同步還是異步?
一對(duì)多,同步
二十. 簡單介紹一下KVC和KVO,他們都可以應(yīng)用在哪些場(chǎng)景?
KVO:鍵值監(jiān)聽,觀察某一屬性的方法
KVC:鍵值編碼,間接訪問對(duì)象的屬性
二十一. 如何添加一個(gè)自定義字體到工程中
> 添加ttf文件,通過[UIFont fontWithName:@“字體名” size:20]使用
二十二. 如何制作一個(gè)靜態(tài)庫/動(dòng)態(tài)庫,他們的區(qū)別是什么?
靜態(tài)庫在編譯時(shí)期:commond+shift+N(即新建工程)----->FrameWork&library—>Cocoa Touch Static Libiary
動(dòng)態(tài)庫在運(yùn)行時(shí)期:commond+shift+N(即新建工程)----->FrameWork&library—>Cocoa Touch Libiary
區(qū)別:靜態(tài)庫:模塊化,分工合作,避免少量改動(dòng),但是會(huì)導(dǎo)致大量的重復(fù)編譯連接,也可以重用,注意不是共享使用 動(dòng)態(tài)庫:可將可執(zhí)行的文件體積縮小,多個(gè)應(yīng)用程序用同一份庫文件,節(jié)省資源
二十三. Configuration中,debug和release的區(qū)別是什么?
debug :測(cè)試時(shí)期,調(diào)試版本,能設(shè)置斷點(diǎn),單步執(zhí)行 release:發(fā)行版本,體積小,運(yùn)行速度快
二十四. 簡單介紹下發(fā)送系統(tǒng)消息的機(jī)制(APNs)
蘋果的APNS不保證送達(dá)率,如你網(wǎng)絡(luò)不好,在APNs那里下線,只保留最后一條消息,并告知推送數(shù),其他消息會(huì)被APNs丟棄。
UI:
二十五. 系統(tǒng)如何尋找到需要響應(yīng)用戶操作的那個(gè)Responder
系統(tǒng)通過調(diào)用hitTest:withEvent:接受位置參數(shù)CGPoint,從底層按照subview的順序,測(cè)試該點(diǎn)在哪個(gè)view上,如果在該view上,則繼續(xù)測(cè)試是否在view的subview上。。。
響應(yīng)鏈?zhǔn)菑牡讓油系?,?dāng)沒有可以處理的responder時(shí)按響應(yīng)鏈往上回溯,一直到application也無人處理則丟棄
二十六. 多屏幕尺寸的適配
Autolayout、Masonry、SDAutoLayout、純Frame計(jì)算比例
二十七. UIButton的父類是什么?UILabel呢?
UIControl UIView
二十八. push view controller 和 present view controller的區(qū)別
是否使用UINavigationController
二十九. 描述下tableview cell的重用機(jī)制
當(dāng)cell被移出界面,進(jìn)入重用池,當(dāng)cell要顯示時(shí)候從重用池中獲取cell
三十. UIView的frame和bounds的區(qū)別是什么
Frame是參考父視圖的坐標(biāo)系,bounds參考自身坐標(biāo)系
三十一. 發(fā)送10個(gè)網(wǎng)絡(luò)請(qǐng)求,然后再接收到所有回應(yīng)之后執(zhí)行后續(xù)操作,如何實(shí)現(xiàn)?
GCD信號(hào)量,隊(duì)列組
- 做法:通過dispatch_group_t來實(shí)現(xiàn),將每個(gè)請(qǐng)求放入到Group中,將合并成大圖的操作放在dispatch_group_notify中實(shí)現(xiàn)。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*加載圖片1 / });
dispatch_group_async(group, queue, ^{ /加載圖片2 / });
dispatch_group_async(group, queue, ^{ /加載圖片3 */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并圖片
});- dispatch_group_enter()和dispatch_group_leave()
三十二. 實(shí)現(xiàn)一個(gè)第三方控件,可以在任何時(shí)候出現(xiàn)在APP界面最上層
三十三. 實(shí)現(xiàn)一個(gè)最簡單的點(diǎn)擊拖拽功能。
三十四. 上面那個(gè)拖拽之外,如果在手放開時(shí),需要根據(jù)速度往前滑動(dòng)呢?
三十五. 如何減小一個(gè)應(yīng)用程序的尺寸?
鏈接:減小iOS App或者靜態(tài)庫體積
鏈接: iOS App 瘦身 - 以 Swift App Yep 為例
三十六. 如何提高一個(gè)應(yīng)用程序的性能?
鏈接:25條提高iOS App性能的建議和技巧
三十七. 不同版本的APP,數(shù)據(jù)庫結(jié)構(gòu)變化了,如何處理?
數(shù)據(jù)庫遷移
- 運(yùn)行APP后,判斷是否存在數(shù)據(jù)庫,不存在則直接創(chuàng)建數(shù)據(jù)庫,若存在取出數(shù)據(jù)庫版本號(hào)進(jìn)行case處理
- 第一次運(yùn)行APP,第一次建立版本庫,將數(shù)據(jù)信息存入數(shù)據(jù)庫,同時(shí)保存一個(gè)當(dāng)前版本加一的字段到數(shù)據(jù)庫中
- 當(dāng)APP更新時(shí),從數(shù)據(jù)庫中取出數(shù)據(jù)庫中保存的版本字段,然后case執(zhí)行相關(guān)方法,修改完數(shù)據(jù)結(jié)構(gòu)以后,再一次將版本字段加一存到數(shù)據(jù)庫中。
鏈接:App升級(jí)時(shí)數(shù)據(jù)庫的遷移更新