前段時(shí)間更新了一篇 給iOS中高級面試官的一份招聘要求 收到很多小伙伴的點(diǎn)贊與關(guān)注跷车∶芮浚可能有很多小伙伴已經(jīng)帶著我在那篇文章給大家提供的一些面試技巧 & 其中的面試題 已經(jīng)開始招聘了只洒!這里應(yīng)大家要求,對里面的面試題提供相關(guān)答案距芬!相信無論是面試官還是求職者都是有所收獲的~~
PS:篇幅有點(diǎn)長涝开,大家可以關(guān)注或者點(diǎn)贊收藏以備不時(shí)之需!?蜃小舀武!
iOS基礎(chǔ)
1:講講你對
atomic
&nonatomic
的理解
- 1寻馏、原子操作對線程安全并無任何安全保證左腔。被
atomic
修飾的屬性(不重載設(shè)置器和訪問器)只保證了對數(shù)據(jù)讀寫的完整性摇锋,也就是原子性肮柜,但是與對象的線程安全無關(guān)。 - 2、線程安全有保障瑞躺、對性能有要求的情況下可使用
nonatomic
替代atomic
拷邢,當(dāng)然也可以一直使用atomic
。 - 3:詳細(xì)參考
2:被
weak
修飾的對象在被釋放的時(shí)候會發(fā)生什么牙咏?是如何實(shí)現(xiàn)的奢浑?知道sideTable
么阵面?里面的結(jié)構(gòu)可以畫出來么授帕?
被weak修飾的對象在被釋放時(shí)候會置為nil丽涩,不同于assign;
Runtime
維護(hù)了一個(gè) weak表
含潘,用于存儲指向某個(gè)對象的所有weak指針
模叙。weak表
其實(shí)是一個(gè) hash(哈希)表
,Key
是所指對象的地址鞋屈,Value
是 weak指針
的地址(這個(gè)地址的值是所指對象指針的地址)數(shù)組范咨。
- 1、初始化時(shí):
runtime
會調(diào)用objc_initWeak函數(shù)
厂庇,初始化一個(gè)新的weak指針
指向?qū)ο蟮牡刂贰?/li> - 2渠啊、添加引用時(shí):
objc_initWeak函數(shù)
會調(diào)用objc_storeWeak() 函數(shù)
,objc_storeWeak()
的作用是更新指針指向权旷,創(chuàng)建對應(yīng)的弱引用表替蛉。 - 3、釋放時(shí)拄氯,調(diào)用
clearDeallocating函數(shù)
躲查。clearDeallocating函數(shù)
首先根據(jù)對象地址獲取所有weak指針地址
的數(shù)組,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil
译柏,最后把這個(gè)entry
從weak表
中刪除镣煮,最后清理對象的記錄。 - 4:詳細(xì)參考
struct SideTable {
// 保證原子操作的自旋鎖
spinlock_t slock;
// 引用計(jì)數(shù)的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
}
struct weak_table_t {
// 保存了所有指向指定對象的 weak 指針
weak_entry_t *weak_entries;
// 存儲空間
size_t num_entries;
// 參與判斷引用計(jì)數(shù)輔助量
uintptr_t mask;
// hash key 最大偏移值
uintptr_t max_hash_displacement;
};
3:
block
用什么修飾鄙麦?strong
可以典唇?
-
block
本身是像對象一樣可以retain
,和release
胯府。但是介衔,block
在創(chuàng)建的時(shí)候,它的內(nèi)存是分配在棧(stack)上骂因,而不是在堆(heap)上炎咖。他本身的作于域是屬于創(chuàng)建時(shí)候的作用域,一旦在創(chuàng)建時(shí)候的作用域外面調(diào)用block將導(dǎo)致程序崩潰侣签。 - 使用
retain
也可以塘装,但是block的retain行為默認(rèn)是用copy的行為實(shí)現(xiàn)的 - 因?yàn)?
block
變量默認(rèn)是聲明為棧變量的,為了能夠在block的聲明域外使用影所,所以要把block
拷貝(copy)到堆蹦肴,所以說為了block
屬性聲明和實(shí)際的操作一致,最好聲明為copy
猴娩。 - 詳細(xì)參考
4:
block
為什么能夠捕獲外界變量阴幌?__block
做了什么事勺阐?
研究Block的捕獲外部變量就要除去函數(shù)參數(shù)這一項(xiàng),下面一一根據(jù)這4種變量類型的捕獲情況進(jìn)行分析矛双。
- 自動(dòng)變量
- 靜態(tài)變量
- 靜態(tài)全局變量
- 全局變量
首先 全局變量global_i
和 靜態(tài)全局變量static_global_j
的值增加渊抽,以及它們被Block
捕獲進(jìn)去,這一點(diǎn)很好理解议忽,因?yàn)槭侨值睦撩疲饔糜蚝軓V,所以Block
捕獲了它們進(jìn)去之后栈幸,在Block
里面進(jìn)行++
操作愤估,Block
結(jié)束之后,它們的值依舊可以得以保存下來速址。
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
__main_block_impl_0結(jié)構(gòu)體
就是這樣把自動(dòng)變量捕獲進(jìn)來的玩焰。也就是說,在執(zhí)行 Block
語法的時(shí)候芍锚,Block
語法表達(dá)式所使用的自動(dòng)變量的值是被保存進(jìn)了Block
的結(jié)構(gòu)體實(shí)例中昔园,也就是 Block
自身中。
這里值得說明的一點(diǎn)是并炮,如果Block
外面還有很多自動(dòng)變量默刚,靜態(tài)變量,等等逃魄,這些變量在Block
里面并不會被使用到羡棵。那么這些變量并不會被Block
捕獲進(jìn)來,也就是說并不會在構(gòu)造函數(shù)里面?zhèn)魅胨鼈兊闹怠?/p>
Block
捕獲外部變量僅僅只捕獲Block
閉包里面會用到的值嗅钻,其他用不到的值,它并不會去捕獲店展。
5:談?wù)勀銓κ录膫鬟f鏈和響應(yīng)鏈的理解
- 一:響應(yīng)者鏈
UIResponser
包括了各種Touch message
的處理养篓,比如開始,移動(dòng)赂蕴,停止等等柳弄。常見的UIResponser
有UIView及子類
,UIViController
,APPDelegate
概说,UIApplication
等等碧注。
回到響應(yīng)鏈,響應(yīng)鏈?zhǔn)怯?code>UIResponser組成的糖赔,那么是按照哪種規(guī)則形成的萍丐。
A: 程序啟動(dòng)
UIApplication
會生成一個(gè)單例,并會關(guān)聯(lián)一個(gè)APPDelegate
放典。APPDelegate
作為整個(gè)響應(yīng)鏈的根建立起來逝变,而``UIApplication會將自己與這個(gè)單例鏈接基茵,即
UIApplication的
nextResponser(下一個(gè)事件處理者)為
APPDelegate`。B:創(chuàng)建UIWindow
程序啟動(dòng)后壳影,任何的UIWindow
被創(chuàng)建時(shí)拱层,UIWindow
內(nèi)部都會把nextResponser
設(shè)置為UIApplication單例
。UIWindow
初始化rootViewController
,rootViewController
的nextResponser
會設(shè)置為UIWindow
C:UIViewController初始化
loadView
,VC
的view
的nextResponser
會被設(shè)置為VC
.D:addSubView
addSubView
操作過程中宴咧,如果子subView不是VC的View,那么subView
的nextResponser
會被設(shè)置為superView
根灯。如果是VC
的View
,那就是subView -> subView.VC ->superView
如果在中途,subView.VC
被釋放掺栅,就會變成subView.nextResponser = superView
我們使用一個(gè)現(xiàn)實(shí)場景來解釋這個(gè)問題:當(dāng)一個(gè)用點(diǎn)擊屏幕上的一個(gè)按鈕烙肺,這個(gè)過程具體發(fā)生了什么。
- 用戶觸摸屏幕柿冲,系統(tǒng)硬件進(jìn)程會獲取到這個(gè)點(diǎn)擊事件茬高,將事件簡單處理封裝后存到系統(tǒng)中,由于硬件檢測進(jìn)程和當(dāng)前App進(jìn)程是兩個(gè)進(jìn)程假抄,所以進(jìn)程兩者之間傳遞事件用的是端口通信怎栽。硬件檢測進(jìn)程會將事件放到
APP
檢測的那個(gè)端口。
- 用戶觸摸屏幕柿冲,系統(tǒng)硬件進(jìn)程會獲取到這個(gè)點(diǎn)擊事件茬高,將事件簡單處理封裝后存到系統(tǒng)中,由于硬件檢測進(jìn)程和當(dāng)前App進(jìn)程是兩個(gè)進(jìn)程假抄,所以進(jìn)程兩者之間傳遞事件用的是端口通信怎栽。硬件檢測進(jìn)程會將事件放到
2.
APP
啟動(dòng)主線程RunLoop
會注冊一個(gè)端口事件宿饱,來檢測觸摸事件的發(fā)生熏瞄。當(dāng)事件到達(dá),系統(tǒng)會喚起當(dāng)前APP
主線程的RunLoop
谬以。來源就是App主線程事件
强饮,主線程會分析這個(gè)事件。3.最后为黎,系統(tǒng)判斷該次觸摸是否導(dǎo)致了一個(gè)新的事件, 也就是說是否是第一個(gè)手指開始觸碰邮丰,如果是,系統(tǒng)會先從響應(yīng)網(wǎng)中 尋找響應(yīng)鏈铭乾。如果不是剪廉,說明該事件是當(dāng)前正在進(jìn)行中的事件產(chǎn)生的一個(gè)
Touch message
, 也就是說已經(jīng)有保存好的響應(yīng)鏈二:事件傳遞鏈
通過兩種方法來做這個(gè)事情炕檩。
// 先判斷點(diǎn)是否在View內(nèi)部斗蒋,然后遍歷subViews
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
//判斷點(diǎn)是否在這個(gè)View內(nèi)部
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; // default returns YES if point is in bounds
A: 流程
1:先判斷該層級是否能夠響應(yīng)
(1.alpha>0.01 2.userInteractionEnabled == YES 3.hidden = NO)
2:判斷改點(diǎn)是否在
view
內(nèi)部,3:如果在那么遍歷子
view
繼續(xù)返回可響應(yīng)的view,直到?jīng)]有笛质。B:常見問題
父view設(shè)置為不可點(diǎn)擊泉沾,子view可以點(diǎn)擊嗎
不可以,hit test 到父view就截止了
子view設(shè)置view不可點(diǎn)擊不影響父類點(diǎn)擊
同父view覆蓋不影響點(diǎn)擊
手勢對responder方法的影響
C:實(shí)際用法
點(diǎn)一一個(gè)圓形控件妇押,如何實(shí)現(xiàn)只點(diǎn)擊圓形區(qū)域有效跷究,重載
pointInside
。此時(shí)可將外部的點(diǎn)也判斷為內(nèi)部的點(diǎn)舆吮,反之也可以揭朝。事件響應(yīng)鏈在復(fù)雜功能界面進(jìn)行不同控件間的通信队贱,簡便某些場景下優(yōu)于代理和
block
6:談?wù)?KVC 以及 KVO 的理解?
7:
RunLoop
的作用是什么潭袱?它的內(nèi)部工作機(jī)制了解么柱嫌?
字面意思是“消息循環(huán)、運(yùn)行循環(huán)”屯换,runloop
內(nèi)部實(shí)際上就是一個(gè)do-while循環(huán)
编丘,它在循環(huán)監(jiān)聽著各種事件源、消息彤悔,對他們進(jìn)行管理并分發(fā)給線程來執(zhí)行嘉抓。
1.通知觀察者將要進(jìn)入運(yùn)行循環(huán)。
線程和 RunLoop 之間是一一對應(yīng)的2.通知觀察者將要處理計(jì)時(shí)器晕窑。
3.通知觀察者任何非基于端口的輸入源即將觸發(fā)抑片。
4.觸發(fā)任何準(zhǔn)備觸發(fā)的基于非端口的輸入源。
5.如果基于端口的輸入源準(zhǔn)備就緒并等待觸發(fā)杨赤,請立即處理該事件敞斋。轉(zhuǎn)到第9步。
6.通知觀察者線程即將睡眠疾牲。
-
7.將線程置于睡眠狀態(tài)植捎,直到發(fā)生以下事件之一:
- 事件到達(dá)基于端口的輸入源。
- 計(jì)時(shí)器運(yùn)行阳柔。
- 為運(yùn)行循環(huán)設(shè)置的超時(shí)值到期焰枢。
- 運(yùn)行循環(huán)被明確喚醒。
8.通知觀察者線程被喚醒舌剂。
-
9.處理待處理事件济锄。
- 如果觸發(fā)了用戶定義的計(jì)時(shí)器,則處理計(jì)時(shí)器事件并重新啟動(dòng)循環(huán)霍转。轉(zhuǎn)到第2步拟淮。
- 如果輸入源被觸發(fā),則傳遞事件谴忧。
- 如果運(yùn)行循環(huán)被明確喚醒但尚未超時(shí),請重新啟動(dòng)循環(huán)角虫。轉(zhuǎn)到第2步沾谓。
10.通知觀察者運(yùn)行循環(huán)已退出。
8:蘋果是如何實(shí)現(xiàn)
autoreleasepool
的戳鹅?
arc下編譯器會優(yōu)化成
void *context = objc_autoreleasePoolPush();
// {}中的代碼
objc_autoreleasePoolPop(context);
- 向一個(gè)結(jié)構(gòu)
AutoreleasePoolPage
均驶,中寫入需要自動(dòng)釋放的對象,類似一種標(biāo)記枫虏,調(diào)用objc_autoreleasePoolPop(context)
后妇穴,就會把這中間的對象release
一下爬虱。 - 這里要注意的是,方法返回值是怎么做到自動(dòng)釋放的腾它?
- 其使用
Thread Local Storage(TLS)
線程局部存儲跑筝,每次存入線程或者從線程取出來。 - 我們沒有卸載
{}
中的自動(dòng)釋放對象瞒滴,會在每個(gè)runloop
結(jié)束時(shí)候去釋放曲梗,相當(dāng)于一個(gè)大的autoreleasepool
中。 - 參考文章
- 蘋果是如何實(shí)現(xiàn)autoreleasepool的
9:談?wù)勀銓?
FRP (函數(shù)響應(yīng)式)
的理解妓忍,延伸一下RxSwift
或者RAC
虏两!
參考文章:RxSwift(1)— 初探
看這一篇文章也就夠了!然后結(jié)合 RxSwift
映射到 RAC
世剖!函數(shù)響應(yīng)式的思想是不變的定罢!至于內(nèi)部的封裝有所不同,但是最終卻是殊途同歸旁瘫!
10:平時(shí)開發(fā)有沒有玩過
Instrument
祖凫?
分析:這里的內(nèi)容非常有意思,對于一個(gè)iOS高級開發(fā)人員境蜕,我覺得還有很有必要掌握的蝙场!尤其開發(fā)3-5年,如果沒有掌握這些內(nèi)容我覺得是不合格的
我個(gè)人建議在掌握面試題的同時(shí)還需要求職者更多的去分析和拓展粱年!比如你的探索思路售滤,你在這個(gè)知識點(diǎn)意外的延伸。還有你再實(shí)際開發(fā)過程的落地台诗!而這些都是加分項(xiàng)完箩!
Runtime
1:什么是 isa,isa 的作用是什么拉队?
2:一個(gè)實(shí)例對象的
isa
指向什么弊知?類對象指向什么?元類isa 指向什么粱快?
- 參考文章
- 實(shí)例對象的
isa
指向類 - 類對象的
isa
指向元類 - 元類isa 指向根元類
3:
objc
中類方法和實(shí)例方法有什么本質(zhì)區(qū)別和聯(lián)系秩彤?
類方法:
- 1.類方法是屬于類對象的
- 2.類方法只能通過類對象調(diào)用
- 3.類方法中的self是類對象
- 4.類方法可以調(diào)用其他的類方法
- 5.類方法中不能訪問成員變量
- 6.類方法中不能直接調(diào)用對象方法
實(shí)例方法:
- 1.實(shí)例方法是屬于實(shí)例對象的
- 2.實(shí)例方法只能通過實(shí)例對象調(diào)用
- 3.實(shí)例方法中的self是實(shí)例對象
- 4.實(shí)例方法中可以訪問成員變量
- 5.實(shí)例方法中直接調(diào)用實(shí)例方法
- 6.實(shí)例方法中也可以調(diào)用類方法(通過類名)
4:
load
和initialize
的區(qū)別?
+load
- 1事哭、只要程序啟動(dòng)就會將所有類的代碼加載到內(nèi)存中(在main函數(shù)執(zhí)行之前), 放到代碼區(qū)(無論該類有沒有被使用到都會被調(diào)用)
- 2漫雷、
+load
方法會在當(dāng)前類被加載到內(nèi)存的時(shí)候調(diào)用, 有且僅會調(diào)用一次 - 3、當(dāng)父類和子類都實(shí)現(xiàn)
+load
方法時(shí), 會先調(diào)用父類的+load
方法, 再調(diào)用子類的+load
方法 - 4鳍咱、先加載原始類降盹,再加載分類的
+load
方法 - 5、子類實(shí)現(xiàn)或不實(shí)現(xiàn)
load
,父類都會調(diào)用load
- 6谤辜、多個(gè)類都實(shí)現(xiàn)
+load
方法蓄坏,+load
方法的調(diào)用順序价捧,與Compile Sources
中出現(xiàn)的順序一致
+initialize
- 1、當(dāng)類第一次被使用的時(shí)候就會調(diào)用(創(chuàng)建類對象的時(shí)候)
- 2涡戳、
initialize
方法在整個(gè)程序的運(yùn)行過程中只會被調(diào)用一次, 無論你使用多少次這個(gè)類都只會調(diào)用一次 - 3结蟋、
initialize
用于對某一個(gè)類進(jìn)行一次性的初始化 - 4、先調(diào)用父類的
initialize
再調(diào)用子類的initialize
- 5妹蔽、當(dāng)子類未實(shí)現(xiàn)
initialize
方法時(shí)椎眯,會把父類的實(shí)現(xiàn)繼承過來調(diào)用一遍,再次之前父類的initialize
方法會被優(yōu)先調(diào)用一次 - 6胳岂、當(dāng)有多個(gè)
Category
都實(shí)現(xiàn)了initialize
方法编整,會覆蓋類中的方法,只執(zhí)行一個(gè)(會執(zhí)行Compile Sources
列表中最后一個(gè)Category
的initialize
方法)
5:
_objc_msgForward
函數(shù)是做什么的乳丰?直接調(diào)用會發(fā)生什么問題掌测?
當(dāng)對象沒有實(shí)現(xiàn)某個(gè)方法 ,會調(diào)用這個(gè)函數(shù)進(jìn)行方法轉(zhuǎn)發(fā)产园。
(某方法對應(yīng)的IMP
沒找到汞斧,會返回這個(gè)函數(shù)的IMP
去執(zhí)行)
- 1.調(diào)用resolveInstanceMethod:方法,允許用戶在此時(shí)為該Class動(dòng)態(tài)添加實(shí)現(xiàn)什燕。如果有實(shí)現(xiàn)了粘勒,則調(diào)用并返回。如果仍沒實(shí)現(xiàn)屎即,繼續(xù)下面的動(dòng)作庙睡。
- 2.調(diào)用forwardingTargetForSelector:方法,嘗試找到一個(gè)能響應(yīng)該消息的對象技俐。如果獲取到乘陪,則直接轉(zhuǎn)發(fā)給它。如果返回了nil雕擂,繼續(xù)下面的動(dòng)作啡邑。
- 3.調(diào)用methodSignatureForSelector:方法,嘗試獲得一個(gè)方法簽名井赌。如果獲取不到谤逼,則直接調(diào)用doesNotRecognizeSelector拋出異常。
- 4.調(diào)用forwardInvocation:方法仇穗,將地3步獲取到的方法簽名包裝成Invocation傳入森缠,如何處理就在這里面了。
如果直接調(diào)用這個(gè)方法仪缸,就算實(shí)現(xiàn)了想調(diào)用的方法,也不會被調(diào)用列肢,會直接走消息轉(zhuǎn)發(fā)步驟恰画。
6:簡述下
Objective-C
中調(diào)用方法的過程
-
Objective-C
是動(dòng)態(tài)語言宾茂,每個(gè)方法在運(yùn)行時(shí)會被動(dòng)態(tài)轉(zhuǎn)為消息發(fā)送,即:objc_msgSend(receiver, selector)
拴还,整個(gè)過程介紹如下: -
objc
在向一個(gè)對象發(fā)送消息時(shí)跨晴,runtime
庫會根據(jù)對象的isa指針找到該對象實(shí)際所屬的類 - 然后在該類中的方法列表以及其父類方法列表中尋找方法運(yùn)行
- 如果,在最頂層的父類(一般也就NSObject)中依然找不到相應(yīng)的方法時(shí)片林,程序在運(yùn)行時(shí)會掛掉并拋出異常
unrecognized selector sent to XXX
- 但是在這之前端盆,objc的運(yùn)行時(shí)會給出三次拯救程序崩潰的機(jī)會,這三次拯救程序奔潰的說明見問題
《什么時(shí)候會報(bào)unrecognized selector的異撤逊猓》
中的說明
PS:Runtime
鑄就了Objective-C
是動(dòng)態(tài)語言的特性焕妙,使得C語言具備了面向?qū)ο蟮奶匦裕诔绦蜻\(yùn)行期創(chuàng)建弓摘,檢查焚鹊,修改類、對象及其對應(yīng)的方法涕刚,這些操作都可以使用runtime中的對應(yīng)方法實(shí)現(xiàn)置谦。
7:能否想向編譯后得到的類中增加實(shí)例變量军洼?能否向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量?為什么璧针?
- 1.不能向編譯后得到的類增加實(shí)例變量
- 2.能向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量
解釋:
- 1.編譯后的類已經(jīng)注冊在
runtime
中,類結(jié)構(gòu)體中的objc_ivar_list
實(shí)例變量的鏈表和instance_size
實(shí)例變量的內(nèi)存大小已經(jīng)確定,runtime
會調(diào)用class_setvarlayout
或class_setWeaklvarLayout
來處理strong weak
引用.所以不能向存在的類中添加實(shí)例變量 - 2.運(yùn)行時(shí)創(chuàng)建的類是可以添加實(shí)例變量,調(diào)用
class_addIvar函數(shù)
.但是的在調(diào)用objc_allocateClassPair
之后,objc_registerClassPair
之前,原因同上.
8:談?wù)勀銓η忻婢幊痰睦斫?/p>
維基百科對于切面編程(AOP)的解釋是這樣的:面向切面的程序設(shè)計(jì)(aspect-oriented programming,AOP
渊啰,又譯作面向側(cè)面的程序設(shè)計(jì)探橱、觀點(diǎn)導(dǎo)向編程、剖面導(dǎo)向程序設(shè)計(jì))是計(jì)算機(jī)科學(xué)中的一個(gè)術(shù)語虽抄,指一種程序設(shè)計(jì)范型走搁。該范型以一種稱為切面的語言構(gòu)造為基礎(chǔ),切面是一種新的模塊化機(jī)制迈窟,用來描述分散在對象私植、類、函數(shù))中的橫切關(guān)注點(diǎn)车酣。參考文章
分析:
Runtime
這個(gè)模塊iOS面試無論初中高都會面試曲稼。我覺得這個(gè)模塊不光只是僅僅問問關(guān)于知識點(diǎn)內(nèi)容,我更新想要聽到求職者在這里面的爬坑探索辛歷路程湖员!Runtime
這個(gè)模塊是刷開頁面開發(fā)的關(guān)鍵點(diǎn)贫悄!
網(wǎng)絡(luò)&多線程
1:HTTP的缺陷是什么?
HTTP 主要有這些不足娘摔,例舉如下窄坦。
- 通信使用明文(不加密),內(nèi)容可能會被竊聽
- 不驗(yàn)證通信方的身份,因此有可能遭遇偽裝
- 無法證明報(bào)文的完整性鸭津,所以有可能已遭篡改
這些問題不僅在HTTP
上出現(xiàn)彤侍,其他未加密的協(xié)議中也會存在這類問題。
2:談?wù)勅挝帐帜媲鳎拇螕]手盏阶!為什么是三次握手,四次揮手闻书?
參考文章 我覺得這個(gè)地方還是需要自我理解名斟,用自己的話去表達(dá)出來!
3:
socket
連接和Http
連接的區(qū)別
http
是基于 socket
之上的魄眉。socket
是一套完整的 tcp,udp
協(xié)議的接口砰盐。
-
HTTP協(xié)議
:簡單對象訪問協(xié)議,對應(yīng)于應(yīng)用層杆融,HTTP
協(xié)議是基于TCP連接的楞卡。- tcp協(xié)議:對應(yīng)于傳輸層。
- ip協(xié)議:對應(yīng)于網(wǎng)絡(luò)層脾歇。
TCP/IP是傳輸層協(xié)議
蒋腮,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸,而HTTP協(xié)議是應(yīng)用層協(xié)議藕各,主要解決如何包裝數(shù)據(jù)池摧。
Socket是對TCP/IP 協(xié)議的封裝
,它本身不是協(xié)議激况,而是一個(gè)調(diào)用接口作彤,通過Socket
,我們才能使用TCP/IP協(xié)議
乌逐。
-
http連接
:就是所謂的短連接竭讳,即客戶端向服務(wù)器端發(fā)送一次請求,服務(wù)器端響應(yīng)后連接即會斷掉浙踢。 - socket連接:就是所謂的長連接绢慢,理論上客戶端和服務(wù)器端一旦建立起連接將不會主動(dòng)斷掉,但是由于各種環(huán)境因素可能會使連接斷開洛波。
http
是客戶端用http
協(xié)議進(jìn)行請求胰舆,發(fā)送請求時(shí)候需要封裝http
請求頭,并綁定請求的數(shù)據(jù)蹬挤,服務(wù)器一般有web
服務(wù)器配合缚窿。http
請求方式為客戶端主動(dòng)發(fā)起請求,服務(wù)器才能給響應(yīng)焰扳,一次請求完畢后則斷開連接以節(jié)省資源倦零。服務(wù)器不能主動(dòng)給客戶端響應(yīng)误续。iPhone
主要使用的類是NSUrlConnection
。socket
是客戶端跟服務(wù)器直接使用socket“套接字”
進(jìn)行拼接扫茅,并沒有規(guī)定連接后斷開女嘲,所以客戶端和服務(wù)器可以保持連接,雙方都可以主動(dòng)發(fā)送數(shù)據(jù)诞帐。一般在游戲開發(fā)或者股票開發(fā)這種即時(shí)性很強(qiáng)的并且保持發(fā)送數(shù)據(jù)量比較大的場合使用。主要類是CFSocketRef爆雹。
- UDP:是用戶數(shù)據(jù)報(bào)協(xié)議:主要用在實(shí)時(shí)性要求高以及對質(zhì)量相對較弱的地方停蕉,但面對現(xiàn)在高質(zhì)量的線路容易丟包。
- TCP:是傳輸控制協(xié)議钙态,是面向連接的慧起,,運(yùn)行環(huán)境必然要求其可靠性不可丟失包有良好的擁塞控制機(jī)制册倒。
4:什么時(shí)候POP網(wǎng)絡(luò)蚓挤,有了
Alamofire
封裝網(wǎng)絡(luò)URLSession
為什么還要用Moya
?
POP網(wǎng)絡(luò)
:面向協(xié)議編程的網(wǎng)絡(luò)能夠大大降低耦合度驻子!網(wǎng)絡(luò)層下沉灿意,業(yè)務(wù)層上浮。中間利用 POP網(wǎng)絡(luò)
的Moya
隔開崇呵。如果你的項(xiàng)目是 RxSwift
函數(shù)響應(yīng)式的也沒有關(guān)系缤剧!因?yàn)橛?RxMoya
參考文章:
5:如何實(shí)現(xiàn)
dispatch_once
+ (instancetype)sharedInstance
{
/*定義相應(yīng)類實(shí)例的靜態(tài)變量;
意義:函數(shù)內(nèi)定義靜態(tài)變量域慷,無論該函數(shù)被調(diào)用多少次荒辕,
在內(nèi)存中只初始化一次,并且能保存最后一次賦的值
*/
static ClassName *instance = nil;
/*定義一個(gè)dispatch_once_t(其實(shí)也就是整型)靜態(tài)變量犹褒,
意義:作為標(biāo)識下面dispatch_once的block是否已執(zhí)行過抵窒。
static修飾會默認(rèn)將其初始化為0,當(dāng)值為0時(shí)才會執(zhí)行block叠骑。
當(dāng)block執(zhí)行完成李皇,底層會將onceToken設(shè)置為1,這也就是為什
么要傳onceToken的地址(static修飾的變量可以通過地址修改
onceToken的值)座云,同時(shí)底層會加鎖來保證這個(gè)方法是線程安全的
*/
static dispatch_once_t onceToken;
/*只要當(dāng)onceToken == 0時(shí)才會執(zhí)行block疙赠,否則直接返回靜態(tài)變量instance*/
dispatch_once(&onceToken, ^{
instance = [[ClassName alloc] init];
//...
});
return instance;
}
iOS原理之CGD-dispatch_once的底層實(shí)現(xiàn)
6:能否寫一個(gè)讀寫鎖?談?wù)劸唧w的分析
7:什么時(shí)候會出現(xiàn)死鎖朦拖?如何避免圃阳?
8:有哪幾種鎖?各自的原理璧帝?它們之間的區(qū)別是什么捍岳?最好可以結(jié)合使用場景來說
分析:這個(gè)模塊可能是一般開發(fā)人員的盲區(qū)。對于這一塊一定要有自己的理解!學(xué)習(xí)的方向就是查漏補(bǔ)缺锣夹,一步一個(gè)吃掉页徐!如果你一整塊去啃,你會發(fā)現(xiàn)很枯燥银萍!雖然開發(fā)過程中你可能用不到变勇,但是面試這一塊是你必須要掌握的!
數(shù)據(jù)結(jié)構(gòu)
1.數(shù)據(jù)結(jié)構(gòu)的存儲一般常用的有幾種贴唇?各有什么特點(diǎn)搀绣?
數(shù)據(jù)的存儲結(jié)構(gòu)是數(shù)據(jù)結(jié)構(gòu)的一個(gè)重要內(nèi)容。在計(jì)算機(jī)中戳气,數(shù)據(jù)的存儲結(jié)構(gòu)可以采取如下四中方法來表現(xiàn)链患。
- 順序存儲方式
簡單的說,順序存儲方式就是在一塊連續(xù)的存儲區(qū)域
一個(gè)接著一個(gè)的存放數(shù)據(jù)瓶您。順序存儲方式把邏輯上相連的結(jié)點(diǎn)存儲在物理位置上相鄰的存儲單元里麻捻,結(jié)點(diǎn)間的邏輯關(guān)系由存儲單元的鄰接掛安息來體現(xiàn)。順序存儲方式也稱為順序存儲結(jié)構(gòu)(sequentialstorage structure)呀袱,一般采用數(shù)組或者結(jié)構(gòu)數(shù)組來描述贸毕。
線性存儲方式主要用于線性邏輯結(jié)構(gòu)的數(shù)據(jù)存放,而對于圖和樹等非線性邏輯結(jié)構(gòu)則不適用压鉴。
- 鏈接存儲方式
鏈接存儲方式比較靈活崖咨,其不要求邏輯上相鄰的結(jié)點(diǎn)在物理位置上相鄰,結(jié)點(diǎn)間的邏輯關(guān)系由附加的引用字段表示油吭。一個(gè)結(jié)點(diǎn)的引用字段往往指導(dǎo)下一個(gè)結(jié)點(diǎn)的存放位置击蹲。
鏈接存儲方式也稱為鏈接式存儲結(jié)構(gòu)(LinkedStorage Structure),一般在原數(shù)據(jù)項(xiàng)中增加應(yīng)用類型來表示結(jié)點(diǎn)之間的位置關(guān)系婉宰。
- 索引存儲方式
索引存儲方式是采用附加索引表的方式來存儲結(jié)點(diǎn)信息的一種存儲方式歌豺。索引表由若干個(gè)索引項(xiàng)組成。索引存儲方式中索引項(xiàng)的一般形式為:(關(guān)鍵字心包、地址)类咧。其中,關(guān)鍵字是能夠唯一標(biāo)識一個(gè)結(jié)點(diǎn)的數(shù)據(jù)項(xiàng)蟹腾。
-
索引存儲方式還可以細(xì)分為如下兩類:
稠密索引(Dense Index):這種方式中每個(gè)結(jié)點(diǎn)在索引表中都有一個(gè)索引項(xiàng)痕惋。其中,索引項(xiàng)的地址指示結(jié)點(diǎn)所在的的存儲位置娃殖;
稀疏索引(Spare Index):這種方式中一組結(jié)點(diǎn)在索引表中只對應(yīng)一個(gè)索引項(xiàng)值戳。其中,索引項(xiàng)的地址指示一組結(jié)點(diǎn)的起始存儲位置炉爆。
散列存儲方式
散列存儲方式是根據(jù)結(jié)點(diǎn)的關(guān)鍵字直接計(jì)算出該結(jié)點(diǎn)的存儲地址的一種存儲的方式堕虹。
在實(shí)際應(yīng)用中卧晓,往往需要根據(jù)具體數(shù)據(jù)結(jié)構(gòu)來決定采用哪一種存儲方式。同一邏輯結(jié)構(gòu)采用不同額存儲方法赴捞,可以得到不同的存儲結(jié)構(gòu)逼裆。而且這四種節(jié)本存儲方法,既可以單獨(dú)使用赦政,也可以組合起來對數(shù)據(jù)結(jié)構(gòu)進(jìn)行存儲描述胜宇。
2.集合結(jié)構(gòu) 線性結(jié)構(gòu) 樹形結(jié)構(gòu) 圖形結(jié)構(gòu)
3.單向鏈表 雙向鏈表 循環(huán)鏈表
4.數(shù)組和鏈表區(qū)別
5.堆、棧和隊(duì)列
- iOS常用算法和數(shù)據(jù)結(jié)構(gòu)
-
數(shù)據(jù)結(jié)構(gòu)初探這里面介紹了很多數(shù)據(jù)結(jié)構(gòu)恢着,大家還可以自行查閱更多資料
6.輸入一棵二叉樹的根結(jié)點(diǎn)掸屡,求該樹的深度?
如果一棵樹只有一個(gè)結(jié)點(diǎn)然评,它的深度為1。 如果根結(jié)點(diǎn)只有左子樹而沒有右子樹狈究, 那么樹的深度應(yīng)該是其左子樹的深度加1碗淌,同樣如果根結(jié)點(diǎn)只有右子樹而沒有左子樹,那么樹的深度應(yīng)該是其右子樹的深度加1. 如果既有右子樹又有左子樹抖锥, 那該樹的深度就是其左亿眠、右子樹深度的較大值再加1。
public static int treeDepth(BinaryTreeNode root) {
if (root == null) {
return 0;
}
int left = treeDepth(root.left);
int right = treeDepth(root.right);
return left > right ? (left + 1) : (right + 1);
}
7.輸入一課二叉樹的根結(jié)點(diǎn)磅废,判斷該樹是不是平衡二叉樹纳像?
- (1)需要重復(fù)遍歷節(jié)點(diǎn)多次的解法
- (2)每個(gè)節(jié)點(diǎn)只需遍歷一次的解法
- 參考文章:
算法
1.時(shí)間復(fù)雜度
在計(jì)算機(jī)科學(xué)中,時(shí)間復(fù)雜性拯勉,又稱時(shí)間復(fù)雜度竟趾,算法的時(shí)間復(fù)雜度是一個(gè)函數(shù),它定性描述該算法的運(yùn)行時(shí)間宫峦。這是一個(gè)代表算法輸入值的字符串的長度的函數(shù)岔帽。時(shí)間復(fù)雜度常用大O符號表述,不包括這個(gè)函數(shù)的低階項(xiàng)和首項(xiàng)系數(shù)导绷。使用這種方式時(shí)犀勒,時(shí)間復(fù)雜度可被稱為是漸近的,亦即考察輸入值大小趨近無窮時(shí)的情況妥曲。
時(shí)間復(fù)雜性
2.空間復(fù)雜度
空間復(fù)雜度(Space Complexity)是對一個(gè)算法在運(yùn)行過程中臨時(shí)占用存儲空間大小的量度贾费,記做S(n)=O(f(n))。比如直接插入排序的時(shí)間復(fù)雜度是O(n^2),空間復(fù)雜度是O(1) 檐盟。而一般的遞歸算法就要有O(n)的空間復(fù)雜度了褂萧,因?yàn)槊看芜f歸都要存儲返回信息。一個(gè)算法的優(yōu)劣主要從算法的執(zhí)行時(shí)間和所需要占用的存儲空間兩個(gè)方面衡量遵堵。
時(shí)間復(fù)雜度&空間復(fù)雜度
3.常用的排序算法
- 1箱玷、冒泡排序
- 2怨规、選擇排序
- 3、插入排序
- 4锡足、希爾排序
- 5波丰、快速排序
- 6、歸并排序
- 7舶得、堆排序
- 常見的7種排序算法
4.字符串反轉(zhuǎn)
- (NSString *)reversalString:(NSString *)originString{
NSString *resultStr = @"";
for (NSInteger i = originString.length -1; i >= 0; i--) {
NSString *indexStr = [originString substringWithRange:NSMakeRange(i, 1)];
resultStr = [resultStr stringByAppendingString:indexStr];
}
return resultStr;
}
5.鏈表反轉(zhuǎn)(頭差法)
public Node reverseList(){
Node cur = head;
Node prev = null;
Node curNext = head.next;
Node reverHead = null;
while(cur!=null){
cur.next = prev;
cur = curNext;
prev = cur;
curNext = curNext.next;
}
reverHead = cur;
return reverHead;
}
> 6.有序數(shù)組合并
```objc
- (void)merge {
/*
有序數(shù)組A:1掰烟、4、5沐批、8纫骑、10...1000000,有序數(shù)組B:2九孩、3先馆、6、7躺彬、9...999998煤墙,A、B兩個(gè)數(shù)組不相互重復(fù)宪拥,請合并成一個(gè)有序數(shù)組C仿野,寫出代碼和時(shí)間復(fù)雜度。
*/
//(1).
NSMutableArray *A = [NSMutableArray arrayWithObjects:@4,@5,@8,@10,@15, nil];
// NSMutableArray *B = [NSMutableArray arrayWithObjects:@2,@6,@7,@9,@11,@17,@18, nil];
NSMutableArray *B = [NSMutableArray arrayWithObjects:@2,@6,@7,@9,@11,@12,@13, nil];
NSMutableArray *C = [NSMutableArray array];
int count = (int)A.count+(int)B.count;
int index = 0;
for (int i = 0; i < count; i++) {
if (A[0]<B[0]) {
[C addObject:A[0]];
[A removeObject:A[0]];
}
else if (B[0]<A[0]) {
[C addObject:B[0]];
[B removeObject:B[0]];
}
if (A.count==0) {
[C addObjectsFromArray:B];
NSLog(@"C = %@",C);
index = i+1;
NSLog(@"index = %d",index);
return;
}
else if (B.count==0) {
[C addObjectsFromArray:A];
NSLog(@"C = %@",C);
index = i+1;
NSLog(@"index = %d",index);
return;
}
}
//(2).
//時(shí)間復(fù)雜度
//T(n) = O(f(n)):用"T(n)"表示她君,"O"為數(shù)學(xué)符號脚作,f(n)為同數(shù)量級,一般是算法中頻度最大的語句頻度缔刹。
//時(shí)間復(fù)雜度:T(n) = O(index);
}
7.查找第一個(gè)只出現(xiàn)一次的字符(Hash查找)
兩個(gè)思路:
- 1:
hash
?不同編譯器對字符數(shù)據(jù)的處理不一樣球涛,所以hash之前先把字符類型轉(zhuǎn)成無符號類型; - 2校镐,空間換時(shí)間宾符,用
buffer數(shù)組
記錄當(dāng)前只找到一次的字符,避免二次遍歷灭翔。
# define SIZE 256
char GetChar(char str[])
{
if(!str)
return 0;
char* p = NULL;
unsigned count[SIZE] = {0};
char buffer[SIZE];
char* q = buffer;
for(p=str; *p!=0; p++)
{
if(++count[(unsigned char)*p] == 1)
*q++ = *p;
}
for (p=buffer; p<q; p++)
{
if(count[(unsigned char)*p] == 1)
return *p;
}
return 0;
}
8.查找兩個(gè)子視圖的共同父視圖
這個(gè)問的其實(shí)是數(shù)據(jù)結(jié)構(gòu)中的二叉樹魏烫,查找一個(gè)普通二叉樹中兩個(gè)節(jié)點(diǎn)最近的公共祖先問題
假設(shè)兩個(gè)視圖為UIViewA
、UIViewC
肝箱,其中 UIViewA
繼承于UIViewB
哄褒,UIViewB
繼承于UIViewD
,UIViewC
也繼承于UIViewD
煌张;即 A->B->D呐赡,C->D
- (void)viewDidLoad {
[super viewDidLoad];
Class commonClass1 = [self commonClass1:[ViewA class] andClass:[ViewC class]];
NSLog(@"%@",commonClass1);
// 輸出:2018-03-22 17:36:01.868966+0800 兩個(gè)UIView的最近公共父類[84288:2458900] ViewD
}
// 獲取所有父類
- (NSArray *)superClasses:(Class)class {
if (class == nil) {
return @[];
}
NSMutableArray *result = [NSMutableArray array];
while (class != nil) {
[result addObject:class];
class = [class superclass];
}
return [result copy];
}
- (Class)commonClass1:(Class)classA andClass:(Class)classB {
NSArray *arr1 = [self superClasses:classA];
NSArray *arr2 = [self superClasses:classB];
for (NSUInteger i = 0; i < arr1.count; ++i) {
Class targetClass = arr1[i];
for (NSUInteger j = 0; j < arr2.count; ++j) {
if (targetClass == arr2[j]) {
return targetClass;
}
}
}
return nil;
}
- 方法一明顯的是兩層for循環(huán),時(shí)間復(fù)雜度為
O(N^2)
一個(gè)改進(jìn)的辦法:我們將一個(gè)路徑中的所有點(diǎn)先放進(jìn)NSSet中.因?yàn)镹SSet的內(nèi)部實(shí)現(xiàn)是一個(gè)hash表骏融,所以查詢元素的時(shí)間的復(fù)雜度變成O(1)
,我們一共有N個(gè)節(jié)點(diǎn)链嘀,所以總時(shí)間復(fù)雜度優(yōu)化到了O(N)
- (Class)commonClass2:(Class)classA andClass:(Class)classB{
NSArray *arr1 = [self superClasses:classA];
NSArray *arr2 = [self superClasses:classB];
NSSet *set = [NSSet setWithArray:arr2];
for (NSUInteger i =0; i<arr1.count; ++i) {
Class targetClass = arr1[i];
if ([set containsObject:targetClass]) {
return targetClass;
}
}
return nil;
}
9.無序數(shù)組中的中位數(shù)(快排思想)
10.給定一個(gè)整數(shù)數(shù)組和一個(gè)目標(biāo)值萌狂,找出數(shù)組中和為目標(biāo)值的兩個(gè)數(shù)。
你可以假設(shè)每個(gè)輸入只對應(yīng)一種答案怀泊,且同樣的元素不能被重復(fù)利用茫藏。
示例:給定nums = [2, 7, 11, 15], target = 9
--- 返回 [0, 1]
思路:
- 第一層for循環(huán)從索引0到倒數(shù)第二個(gè)索引拿到每個(gè)數(shù)組元素,
- 第二個(gè)for循環(huán)遍歷上一層for循環(huán)拿到的元素的后面的所有元素霹琼。
- 參考文章
class Solution {
public int[] twoSum(int[] nums, int target) {
int len = nums.length;
int[] result = new int[2];
for(int i = 0; i < len; i++){
for(int j = i+1; j < len; j++){
if(nums[i] + nums[j] == target){
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
}
}
分析:這個(gè)模塊是絕大部分開發(fā)人員的軟肋务傲!這個(gè)模塊是最能測試求職者思維能力的!但是我不建議面試官直接讓求職者手寫 在那樣的面試緊張環(huán)境枣申,手寫數(shù)據(jù)結(jié)構(gòu)或者一些算法代碼售葡,是非常有挑戰(zhàn)的!思維到我覺得差不多忠藤!
架構(gòu)設(shè)計(jì)
1:設(shè)計(jì)模式是為了解決什么問題的挟伙?
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的模孩、經(jīng)過分類編目的像寒、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼瓜贾、讓代碼更容易被他人理解、保證代碼可靠性携悯。
設(shè)計(jì)模式最主要解決的問題是通過封裝和隔離變化點(diǎn)來處理軟件的各種變化問題祭芦。
隔離變化的好處在于,將系統(tǒng)中經(jīng)常變化的部分和穩(wěn)定的部分隔離憔鬼,有助于增加復(fù)用性龟劲,并降低系統(tǒng)耦合度。很多設(shè)計(jì)模式的意圖中都明顯地指出了其對問題的解決方案轴或,學(xué)習(xí)設(shè)計(jì)模式的要點(diǎn)是發(fā)現(xiàn)其解決方案中封裝的變化點(diǎn)昌跌。
三本經(jīng)典書籍:《GOF設(shè)計(jì)模式》,《設(shè)計(jì)模式解析》照雁,《Head First Design Pattern》
設(shè)計(jì)模式是軟件開發(fā)領(lǐng)域的精髓之一蚕愤。學(xué)好設(shè)計(jì)模式是目前每一個(gè)開發(fā)人員的必修課,
2:看過哪些第三方框架的源碼饺蚊,它們是怎么設(shè)計(jì)的萍诱?
這個(gè)題目就看你個(gè)人的感觸,考量你平時(shí)的功底污呼!
大家可以針對性一些常見的框架:RxSwift
裕坊、Alamofire
、Moya
燕酷、AFNetworing
籍凝、YYKit
.... 掌握會用的同時(shí)周瞎,必須要掌握底層的核心思想!
3:可以說幾個(gè)重構(gòu)的技巧么饵蒂?你覺得重構(gòu)適合什么時(shí)候來做声诸?
- 重復(fù)代碼的提煉
- 冗長方法的分割
- 嵌套條件分支的優(yōu)化
- 去掉一次性的臨時(shí)變量
- 消除過長參數(shù)列表
- 提取類或繼承體系中的常量
- 讓類提供應(yīng)該提供的方法
- 拆分冗長的類
- 提取繼承體系中重復(fù)的屬性與方法到父類
在新功能增加時(shí)候,在擴(kuò)展不再簡單的時(shí)候苹享。重構(gòu)是一個(gè)不斷的過程双絮。
4:開發(fā)中常用架構(gòu)設(shè)計(jì)模式你怎么選型?
這里也是一道開放性題目!并不是說某一種架構(gòu)就是最優(yōu)秀的~只有最合適的得问!根據(jù)公司情況囤攀,項(xiàng)目現(xiàn)狀,以及開發(fā)者水平及時(shí)調(diào)整宫纬,設(shè)計(jì)焚挠!
5:你是如何組件化解耦的?
iOS 解藕
漓骚、組件化最常用的是使用統(tǒng)跳路由的方式蝌衔,目前比較常用的 iOS 開源路由框架主要是JLRoutes
、MGJRouter
蝌蹂、HHRouter
等噩斟,這些路由框架各有優(yōu)點(diǎn)和缺點(diǎn),基本可以滿足大部分需求孤个。目前最常用來作路由跳轉(zhuǎn)剃允,以實(shí)現(xiàn)基本的組件化開發(fā),實(shí)現(xiàn)各模塊之間的解藕齐鲤。但是斥废,在實(shí)際中開發(fā)中會發(fā)現(xiàn),無法徹底使用它們完成所有模塊間通信给郊,比如模塊間的同步牡肉、異步通信等。再比如淆九,我們在配置了相關(guān)路由跳轉(zhuǎn)的 URL 后统锤,如何在上線之后動(dòng)態(tài)修改相關(guān)跳轉(zhuǎn)邏輯?在模塊間通信時(shí)炭庙,如何在上線后動(dòng)態(tài)修改相關(guān)參數(shù)跪另?APP 能否實(shí)現(xiàn)類似 Web 的302跳轉(zhuǎn)
?學(xué)習(xí)參考
分析:架構(gòu)設(shè)計(jì)這一層對于一個(gè)iOS中高級開發(fā)人員來說煤搜。這一塊那是他必須要去思考和感受總結(jié)的!如果這位求職者開發(fā)4-5年了免绿,一直都在做應(yīng)用層界面開發(fā),那么想必他未來的職業(yè)晉升是已經(jīng)落后了的擦盾!面試官不妨在這一個(gè)模塊單獨(dú)設(shè)計(jì)成一面嘲驾,就和求職者一起交流討論淌哟。畢竟這些思維的設(shè)計(jì),也許能夠給面試官帶來一些不一樣的東西辽故!??
性能優(yōu)化
1:
tableView
有什么好的性能優(yōu)化方案徒仓?2: 界面卡頓和檢測你都是怎么處理?
3:談?wù)勀銓﹄x屏渲染的理解誊垢?
4:如何降低APP包的大小
5:日常如何檢查內(nèi)存泄露掉弛?
6:APP啟動(dòng)時(shí)間應(yīng)從哪些方面優(yōu)化?
- iOS_tableView性能優(yōu)化
- iOS 版界面卡頓監(jiān)測方案
- iOS 關(guān)于離屏渲染的理解 以及解決方案
- iOS 如何減小app的大小
- iOS 內(nèi)存泄漏檢測方法
- iOS app 啟動(dòng)時(shí)間優(yōu)化分析
分析:現(xiàn)在APP性能優(yōu)化已經(jīng)成為iOS中高級開發(fā)人員必須要去關(guān)系的東西喂走!這一塊我個(gè)人建議結(jié)合實(shí)際開發(fā)去和求職者交流殃饿。而不是僅僅停留在知識點(diǎn)問答,因?yàn)闆]有實(shí)際開發(fā)能力的性能優(yōu)化都只是紙上談兵芋肠!
總結(jié)
這一套面試題還是有一定的水平和難度的乎芳!但是對于要應(yīng)聘一份iOS中高級開發(fā)崗位,還是比較中肯的帖池!希望大家能夠在接下來的跳槽漲薪有自己的思想奈惑。
文章有長,建議關(guān)注備份睡汹,不管是正在面試還是即將面試肴甸,應(yīng)該對你有幫助!既然看到這里:麻煩點(diǎn)個(gè)贊吧囚巴!??
PS:對本文內(nèi)容存在疑問還望指出原在,謝謝!加油文兢,靜候你的佳音