關(guān)于面試題
打個比方鳖昌,如果把找工作理解成考大學(xué)备畦,面試就是高考,市面上的“真題”就是模擬試卷许昨。我們會很容易傾向于在面試前尋找對應(yīng)公司的面試“真題”懂盐,重點(diǎn)準(zhǔn)備,期待“押題”成功糕档。但實(shí)際上允粤,即使面試同一家公司,它會有不同部門翼岁,不同業(yè)務(wù)線,不同面試官司光,即使遇到同一面試官琅坡,他也不一定就每次考察完全一樣的內(nèi)容。想想高考中那些考的好的同學(xué)残家,他們肯定不是靠“押題”才能取得好成績吧榆俺,他們大多靠的是平常積累及對知識點(diǎn)靈活掌握,那面試也一樣啊坞淮。執(zhí)著于搜題茴晋,把面試題當(dāng)做重點(diǎn)進(jìn)行“復(fù)習(xí)”,還不如自己劃出“考綱”回窘,各個知識點(diǎn)逐一檢查掌握情況诺擅,復(fù)習(xí)的更全面呢。
我對于面試題的看法一直是相對保守的啡直,這類文章一般只是內(nèi)容搬運(yùn)烁涌,它會存在一些偏差和誤讀,最重要的那就是幾道題往那一扔酒觅,并沒有產(chǎn)出有價值的東西撮执。這也是為什么我上篇面試總結(jié),會加了一些面試技巧舷丹,整理面試題時抒钱,也沒提他們是出自哪家公司,就是不希望大家把題目區(qū)別看待颜凯。
說了這些并不是說面試題沒用啊谋币,而是希望大家不要迷信面試題,更多地去關(guān)注那些有質(zhì)量有深度的技術(shù)文章装获。面試考核的是知識點(diǎn)而不是具體的某些題目瑞信,面試題的作用在于,衡量我們的知識掌握情況穴豫,便于我們查漏補(bǔ)缺凡简,越說越像是針對一次“考試”了??逼友。
總結(jié)不易,希望這份參考答案能對你有所幫助秤涩,如果想持續(xù)關(guān)注我帜乞,歡迎訂閱微信公眾號:iOS成長之路。
面試題及參考答案
Swift
1筐眷、Swift中struct和class有什么區(qū)別黎烈?
struct是值引用,更輕量匀谣,存放于棧區(qū)照棋,class是類型引用,存放于堆區(qū)武翎。struct無法繼承烈炭,class可繼承。
2宝恶、Swift中的方法調(diào)用有哪些形式符隙?
答:直接派發(fā)、函數(shù)表派發(fā)垫毙、消息機(jī)制派發(fā)霹疫。派發(fā)方式受聲明位置,引用類型综芥,特定行為的影響丽蝎。為什么Swift有這么多派發(fā)形式?為了效率膀藐。
參考文章:深入理解 Swift 派發(fā)機(jī)制
3征峦、Swift和OC有什么區(qū)別?
Swift和OC的區(qū)別有很多消请,這里簡要總結(jié)這幾條:
**Swift**? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? **Objective-C**復(fù)制代碼
語言特性 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 靜態(tài)語言栏笆,更加安全? ? ? ? ? 動態(tài)語言,不那么安全
語法 ? ? ? ? 更精簡? ? ? ? ? ? ? ? ? ? ? ? 冗長
命名空間 ? ? 有? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 無
方法調(diào)用 直接調(diào)用臊泰,函數(shù)表調(diào)用蛉加,消息轉(zhuǎn)發(fā) 消息轉(zhuǎn)發(fā)
泛型/元組/高階函數(shù) 有 無
語言效率 性能更高,速度更快 略低
文件特性 .swift 單文件 .h/.m包含頭文件
編程特性 可以更好的實(shí)現(xiàn)函數(shù)式編程/響應(yīng)式編程 面向?qū)ο缶幊?
4缸逃、從OC向Swift遷移的時候遇到過什么問題针饥?
可以參考這篇文章:OC項目轉(zhuǎn)Swift指南 里的混編注意事項。
5需频、怎么理解面向協(xié)議編程丁眼?
面向?qū)ο笫且詫ο蟮囊暯怯^察整體結(jié)構(gòu),萬物皆為對象昭殉。
面向協(xié)議則是用協(xié)議的方式組織各個類的關(guān)系苞七,Swift底層幾乎所有類都構(gòu)建在協(xié)議之上藐守。
面向協(xié)議能夠解決面向?qū)ο蟮牧庑卫^承,橫切關(guān)注點(diǎn)和動態(tài)派發(fā)的安全性等問題蹂风。
參考喵神的面向協(xié)議編程與 Cocoa 的邂逅 (上)
OC語法
1卢厂、Block是如何實(shí)現(xiàn)的?Block對應(yīng)的數(shù)據(jù)結(jié)構(gòu)是什么樣子的惠啄?__block的作用是什么慎恒?它對應(yīng)的數(shù)據(jù)結(jié)構(gòu)又是什么樣子的?
block本質(zhì)是一個對象撵渡,底層用struct實(shí)現(xiàn)融柬。
數(shù)據(jù)結(jié)構(gòu)如下:
struct Block_descriptor {? ? unsigned long int reserved;? ? unsigned long int size;? ? void (*copy)(void *dst, void *src);? ? void (*dispose)(void *);};struct Block_layout {? ? void *isa;? ? int flags;? ? int reserved;? ? void (*invoke)(void *, ...);? ? struct Block_descriptor *descriptor;? ? /* Imported variables. */復(fù)制代碼
·isa 指針,所有對象都有該指針趋距,用于實(shí)現(xiàn)對象相關(guān)的功能丹鸿。
·flags,用于按 bit 位表示一些 block 的附加信息棚品,本文后面介紹 block copy 的實(shí)現(xiàn)代碼可以看到對該變量的使用。
·reserved廊敌,保留變量铜跑。
·invoke,函數(shù)指針骡澈,指向具體的 block 實(shí)現(xiàn)的函數(shù)調(diào)用地址锅纺。
·descriptor, 表示該 block 的附加描述信息肋殴,主要是 size 大小囤锉,以及 copy 和 dispose 函數(shù)的指針。
·variables护锤,capture 過來的變量官地,block 能夠訪問它外部的局部變量,就是因為將這些變量(或變量的地址)復(fù)制到了結(jié)構(gòu)體中烙懦。
__block的作用是讓block可以捕獲該變量驱入,捕獲之后的變量會進(jìn)入到block內(nèi)部,通過反編譯的代碼我們可以看到該對象是這樣的:
struct __Block_byref_i_0 {? ? void *__isa;? ? __Block_byref_i_0 *__forwarding;? ? int __flags;? ? int __size;? ? int val; //變量名};復(fù)制代碼
對于block的深入了解氯析,可以參考《Objective-C高級編程》第二章或者唐巧的這篇談Objective-C block的實(shí)現(xiàn)
2亏较、GCD中的Block是在堆上還是棧上?
堆上掩缓⊙┣椋可以通過block的isa指針確認(rèn)。
3你辣、NSCoding協(xié)議是干什么用的巡通?
一種編碼協(xié)議尘执,歸檔時和解檔時需要依賴該協(xié)議定義的編碼和解碼方法。Foundation和Cocoa Touch中的大部分類都遵循了這個協(xié)議扁达,一般被NSKeyedArchiver做自定義對象持久化時使用正卧。
4、KVO的實(shí)現(xiàn)原理
利用Runtime生成一個中間對象跪解,讓原對象的isa指針指向它炉旷,然后重寫setter方法,插入willChangeValueForKey和didChangeValueForKey方法叉讥。當(dāng)屬性變化時會調(diào)用窘行,會調(diào)用這兩個方法通知到外界屬性變化。
5图仓、NSOperation有哪些特性罐盔,比著GCD有哪些優(yōu)點(diǎn),它有哪些API救崔?
NSOperation是對GCD的封裝惶看,具有面向?qū)ο蟮奶攸c(diǎn),可以更方便的進(jìn)行封裝,可以設(shè)置依賴關(guān)系。
API可以查看NSOperation文檔棉安。
6砾医、NSNotificaiton是同步還是異步的,如果發(fā)通知時在子線程,接收在哪個線程?
同步。子線程冠息。
UI
1、事件響應(yīng)鏈?zhǔn)侨绾蝹鬟f的孕索?
手勢的點(diǎn)擊會發(fā)生兩個重要事情逛艰,事件傳遞和事件響應(yīng)。
事件傳遞:從UIApplication開始搞旭,到window瓮孙,再逐步往下層(子視圖)找,直到找到最深層的子視圖选脊,其為first responder杭抠。用到的判斷方法是pointInside:withEvent和hitTest:withEvent。
事件響應(yīng):從識別到的視圖(first responder)開始驗證能否響應(yīng)事件恳啥,如果不能就交給其上層(父視圖)視圖偏灿,如果能相應(yīng)將不再往下傳遞,如果直到找到UIApplication層還沒有相應(yīng)钝的,那就忽略蓋茨點(diǎn)擊翁垂。用到的判斷方法是touchesBegan:withEvent铆遭、touchesMoved:withEvent等。
這兩個過程大致的相反的沿猜。
2枚荣、什么是異步渲染?
異步渲染就是在子線程進(jìn)行繪制啼肩,然后拿到主線程顯示橄妆。
UIView的顯示是通過CALayer實(shí)現(xiàn)的,CALayer的顯示則是通過contents進(jìn)行的祈坠。異步渲染的實(shí)現(xiàn)原理是當(dāng)我們改變UIView的frame時害碾,會調(diào)用layer的setNeedsDisplay,然后調(diào)用layer的display方法赦拘。我們不能在非主線程將內(nèi)容繪制到layer的context上慌随,但我們單獨(dú)開一個子線程通過CGBitmapContextCreateImage()繪制內(nèi)容,繪制完成之后切回主線程躺同,將內(nèi)容賦值到contents上阁猜。
這個步驟可以參照YYText中YYTextAsyncLayer.m文件中的實(shí)現(xiàn)方式。
3蹋艺、layoutsubviews是在什么時機(jī)調(diào)用的剃袍?
·init初始化不會觸發(fā)。
·addSubview時车海。
·設(shè)置frame且前后值變化,frame為zero且不添加到指定視圖不會觸發(fā)隘击。
·旋轉(zhuǎn)Screen會觸發(fā)父視圖的layoutSubviews侍芝。
·滾動UIScrollView引起View重新布局時會觸發(fā)layoutSubviews。
4埋同、一張圖片的展示經(jīng)歷了哪些步驟州叠?
這個可以參考我之前寫的一篇文章iOS開發(fā)圖片格式選擇 中的前半部分內(nèi)容。
5凶赁、什么是離屏渲染咧栗,什么情況會導(dǎo)致離屏渲染?
如果要在顯示屏上顯示內(nèi)容虱肄,我們至少需要一塊與屏幕像素數(shù)據(jù)量一樣大的frame buffer致板,作為像素數(shù)據(jù)存儲區(qū)域。如果有時因為面臨一些限制咏窿,無法把渲染結(jié)果直接寫入frame buffer斟或,而是先暫存在另外的內(nèi)存區(qū)域,之后再寫入frame buffer集嵌,那么這個過程被稱之為離屏渲染萝挤。
以陰影為例御毅,為什么它會導(dǎo)致離屏渲染。因為GPU的渲染是遵循“畫家算法”怜珍,一層一層繪制的端蛆,但陰影很特殊,它需要全部內(nèi)容繪制完成酥泛,再根據(jù)外輪廓進(jìn)行繪制今豆。這就導(dǎo)致了,陰影這一層要一直占據(jù)一塊內(nèi)存區(qū)域揭璃,這就導(dǎo)致了離屏渲染晚凿。
類似導(dǎo)致離屏渲染的情況還有:
·cornerRadius+clipsToBounds·group opacity 組透明度·mask 遮罩·UIBlurEffect 毛玻璃效果
有一篇文章詳細(xì)的討論了這些情況:關(guān)于iOS離屏渲染的深入研究
6、CoreAnimation這個框架的作用什么瘦馍,它跟UIKit的關(guān)系是什么歼秽?
CoreAnimation雖然直譯是核心動畫,但它其實(shí)是一個圖像渲染框架情组,動畫實(shí)現(xiàn)只是它的一部分功能燥筷。
看這張圖我們可以知道,它是UIKit和AppKit的底層實(shí)現(xiàn)院崇,位于Metal肆氓、Core Graphics和GPU之上之上。
蘋果官方文檔:About Core Animation
引用計數(shù)
1底瓣、ARC方案的原理是什么谢揪?它是在什么時候做的隱式添加release操作?
ARC(Automatic Reference Cunting)自動引用計數(shù)捐凭,意即通過LLVM編譯器自動管理對應(yīng)的引用計數(shù)狀態(tài)拨扶。ARC開啟時無需再次鍵入retain或者release代碼。
它是在編譯階段添加retain或者release代碼的茁肠。
2患民、循環(huán)引用有哪些場景,如何避免垦梆?
循環(huán)引用及兩個及以上對象出現(xiàn)引用環(huán)匹颤,導(dǎo)致對象無法釋放的情況。一般在block托猩,delegate印蓖,NSTimer時容易出現(xiàn)這個問題。
解決方案就是讓環(huán)的其中一環(huán)節(jié)實(shí)現(xiàn)弱引用京腥。
3另伍、為什么當(dāng)我們在使用block時外面是weak 聲明一個weakSelf,還要在block內(nèi)部使用strong再持有一下?
block外界聲明weak是為了實(shí)現(xiàn)block對對象的弱持有摆尝,而里面的作用是為了保證在進(jìn)到block時不會發(fā)生釋放温艇。
4、Autoreleasepool是實(shí)現(xiàn)機(jī)制是什么堕汞?它是什么時候釋放內(nèi)部的對象的勺爱?它內(nèi)部的數(shù)據(jù)結(jié)構(gòu)是什么樣的?當(dāng)我提到哨兵對象時琐鲁,會繼續(xù)問哨兵對象的作用是什么人灼,為什么要設(shè)計它?
Autoreleasepool的原理是一個雙向列表投放,它會對加入其中的對象實(shí)現(xiàn)延遲釋放奈泪。當(dāng)Autoreleasepool調(diào)用drain方法時會釋放內(nèi)部標(biāo)記為autorelease的對象灸芳。
class AutoreleasePoolPage {? ? magic_t const magic;? ? id *next;? ? pthread_t const thread;? ? AutoreleasePoolPage * const parent;? ? AutoreleasePoolPage *child;? ? uint32_t const depth;? ? uint32_t hiwat;};復(fù)制代碼
哨兵對象類似一個指針,指向自動釋放池的棧頂位置烙样,它的作用就是用于標(biāo)記當(dāng)前自動釋放池需要釋放內(nèi)部對象時冯遂,釋放到那個地方結(jié)束谒获,每次入棧時它用于確定添加的位置批狱,然后再次移動到棧頂。
關(guān)于自動釋放池的底層探究可以看draveness的這篇自動釋放池的前世今生 ---- 深入解析 autoreleasepool
5狼速、哪些對象會放入到Autoreleasepool中卦停?
有兩種情況生成的對象會加入到autoreleasepool中:
·非alloc/new/copy/mutablecopy 開始的方式初始化時惊完。·id的指針或?qū)ο蟮闹羔樤跊]有顯示指定時
引用計數(shù)帶來的一次討論
6处硬、weak的實(shí)現(xiàn)原理是什么?當(dāng)引用對象銷毀是它是如何管理內(nèi)部的Hash表的件豌?(這里要參閱weak源碼)
runTime會把對weak修飾的對象放到一個全局的哈希表中控嗜,用weak修飾的對象的內(nèi)存地址為key疆栏,weak指針為值曾掂,在對象進(jìn)行銷毀時珠洗,用通過自身地址去哈希表中查找到所有指向此對象的weak指針若专,并把所有的weak指針置位nil富岳。
Runtime
1、消息發(fā)送的流程是怎樣的蚁飒?
OC中的方法調(diào)用會轉(zhuǎn)化成給對象發(fā)送消息淮逻,發(fā)送消息會調(diào)用這個方法:
復(fù)制代碼
該過程有以下關(guān)鍵步驟:
·先確定調(diào)用方法的類已經(jīng)都加載完畢阁簸,如果沒加載完畢的話進(jìn)行加載
·從cache中查找方法
·cache中沒有找到對應(yīng)的方法启妹,則到方法列表中查,查到則緩存
·如果本類中查詢到?jīng)]有結(jié)果桨啃,則遍歷所有父類重復(fù)上面的查找過程照瘾,直到NSObject
2丧慈、關(guān)聯(lián)對象時什么情況下會導(dǎo)致內(nèi)存泄露?
關(guān)聯(lián)對象可以理解就是持有了一個對象簇搅,如果是retain等方式的持有软吐,而該對象也持有了本類关噪,那就是導(dǎo)致了循環(huán)引用。
3建钥、消息轉(zhuǎn)發(fā)的流程是什么熊经?
消息轉(zhuǎn)發(fā)是發(fā)生在接收者(receiver)沒有找到對應(yīng)的方法(method)的時候欲险,該步驟有如下幾個關(guān)鍵步驟:
·消息轉(zhuǎn)發(fā)的時候天试,如果是實(shí)例方法會走resolveInstanceMethod:喜每,如果是類方法會走resolveClassMethod:,它們的返回值都是Bool枫笛,需要我們確定是否進(jìn)行轉(zhuǎn)發(fā)刑巧。
·如果第一步返回YES无畔,確定轉(zhuǎn)發(fā)就會進(jìn)到下個方法forwardingTargetForSelector檩互,這個方法需要我們指定一個被用receiver咨演。
·methodSignatureForSelector用于指定方法簽名,forwardInvocation用于處理Invocation拍嵌,進(jìn)行完整轉(zhuǎn)發(fā)循诉。
·如果消息轉(zhuǎn)發(fā)也沒有處理即為無法處理茄猫,會調(diào)用doesNotRecognizeSelector划纽,引發(fā)崩潰。
·更多了解可以參考iOS開發(fā)·runtime原理與實(shí)踐: 消息轉(zhuǎn)發(fā)篇(Message Forwarding) (消息機(jī)制靖避,方法未實(shí)現(xiàn)+API不兼容奔潰幻捏,模擬多繼承)
4命咐、category能否添加屬性醋奠,為什么?能否添加實(shí)例變量讽坏,為什么路呜?
可以添加屬性织咧,這里的屬性指@property笙蒙,但跟類里的@property又不一樣捅位。正常的@property為:實(shí)例變量Ivar + Setter + Getter 方法搂抒,分類里的@property這三者都沒有求晶,需要我們手動實(shí)現(xiàn)芳杏。
分類是運(yùn)行時被編譯的辟宗,這時類的結(jié)構(gòu)已經(jīng)固定了泊脐,所以我們無法添加實(shí)例變量晨抡。
對于分類自定義Setter和Getter方法,我們可以通過關(guān)聯(lián)對象(Associated Object)進(jìn)行實(shí)現(xiàn)如捅。
5镜遣、元類的作用是什么士袄?
元類的作用是存儲類方法娄柳,同時它也是為了讓OC的類結(jié)構(gòu)能夠形成閉環(huán)赤拒。
對于為甚設(shè)計元類有以下原因;
·在OC的世界里一切皆對象(借鑒于Smalltalk)这敬,metaclass的設(shè)計就是要為滿足這一點(diǎn)崔涂。
·在OC中Class也是一種對象冷蚂,它對應(yīng)的類就是metaclass,metaclass也是一種對象,它的類是root metaclass尸闸,在往上根元類(root metaclass)指向自己吮廉,形成了一個閉環(huán)畸肆,一個完備的設(shè)計轴脐。**
如果不要metaclass可不可以大咱?也是可以的碴巾,在objc_class再加一個類方法指針厦瓢。但是這樣的設(shè)計會將消息傳遞的過程復(fù)雜化,所以為了消息傳遞流程的復(fù)用劳跃,為了一切皆對象的思想售碳,就有了metaclass贸人。
關(guān)于這一話題的深入討論可以參考這兩篇文章:
為什么要存在MetaClass
為什么要設(shè)計metaclass
6佃声、類方法是存儲到什么地方的圾亏?類屬性呢?
類方法和類屬性都是存儲到元類中的奕枢。
類屬性在Swift用的多些,OC中很少有人用到捧杉,但其實(shí)它也是有的秘血,寫法如下:
@interface Person : NSObject// 在屬性類別中加上class@property (class, nonatomic, copy) NSString *name;@end// 調(diào)用方式NSString *temp = Person.name;復(fù)制代碼
需要注意的是跟實(shí)例屬性不一樣灰粮,類屬性不會自動生成實(shí)例變量和setter粘舟,getter方法柑肴,需要我們手動實(shí)現(xiàn)。具體實(shí)現(xiàn)方法可以參考這個文章:Objective-C Class Properties
7零聚、講幾個runtime的應(yīng)用場景
·hook系統(tǒng)方法進(jìn)行方法交換隶症。
·了解一個類(閉源)的私有屬性和方法蚂会。
·關(guān)聯(lián)對象耗式,實(shí)現(xiàn)添加分類屬性的功能刊咳。
·修改isa指針娱挨,自定義KVO跷坝。
Runloop
1、講一下對Runloop的理解淮韭?
Runloop就是一個運(yùn)行循環(huán)靠粪,它保證了在沒有任務(wù)的時候線程不退出庇配,有任務(wù)的時候即使響應(yīng)捞慌。Runloop跟線程啸澡,事件響應(yīng)氮帐,手勢識別上沐,頁面更新,定時器都有著緊密聯(lián)系龄广。
深入了解推薦ibireme的這篇深入理解RunLoop
2蕴侧、可以用Runloop實(shí)現(xiàn)什么功能净宵?
·檢測卡頓
·線程包活
·性能優(yōu)化择葡,將一些耗時操作放到runloop wait的情況處理。
性能優(yōu)化
1脏里、對TableView進(jìn)行性能優(yōu)化有哪些方式迫横?
·緩存高度
·異步渲染
·減少離屏渲染
2矾踱、Xcode的Instruments都有哪些調(diào)試的工具呛讲?
**·Activity Monitor(活動監(jiān)視器):監(jiān)控進(jìn)程的CPU贝搁、內(nèi)存雷逆、磁盤膀哲、網(wǎng)絡(luò)使用情況某宪。是程序在手機(jī)
運(yùn)行真正占用內(nèi)存大小**
·Allocations(內(nèi)存分配):跟蹤過程的匿名虛擬內(nèi)存和堆的對象提供類名和可選保留/釋放歷史
·Core Animation(圖形性能):顯示程序顯卡性能以及CPU使用情況
·Core Data:跟蹤C(jī)ore Data文件系統(tǒng)活動
·Energy Log:耗電量監(jiān)控
·File Activity:檢測文件創(chuàng)建兴喂、移動衣迷、變化、刪除等
·Leaks(泄漏):一般的措施內(nèi)存使用情況滴肿,檢查泄漏的內(nèi)存泼差,并提供了所有活動的分配和泄漏模塊的類對象分配統(tǒng)計信息以及內(nèi)存地址歷史記錄
·Network:用鏈接工具分析你的程序如何使用TCP/IP和UDP/IP鏈接
·System Usage:記錄關(guān)于文件讀寫堆缘,sockets吼肥,I/O系統(tǒng)活動缀皱,輸入輸出
·Time Profiler(時間探查):方法執(zhí)行耗時分析
·Zombies:測量一般的內(nèi)存使用啤斗,專注于檢測過度釋放的野指針對象钮莲。也提供對象分配統(tǒng)計以及主動分配的內(nèi)存地址歷史
3崔拥、講一下你做過的性能優(yōu)化的事情。
這個根據(jù)自己情況來說吧拆魏。
4稽揭、如何檢測卡頓,都有哪些方法步鉴?
·FPS氛琢,通過CADisplayLink計算1s內(nèi)刷新次數(shù)阳似,也可以利用Instruments里的Core Animation撮奏。
·利用Runloop畜吊,實(shí)時計算 kCFRunLoopBeforeSources 和 kCFRunLoopAfterWaiting 兩個狀態(tài)區(qū)域之間的耗時是否超過某個閥值
·子線程檢測玲献,每次檢測時設(shè)置標(biāo)記位為YES捌年,然后派發(fā)任務(wù)到主線程中將標(biāo)記位設(shè)置為NO礼预。接著子線程沉睡超時闕值時長逆瑞,判斷標(biāo)志位是否成功設(shè)置成NO,如果沒有說明主線程發(fā)生了卡頓哈肖。參考ANREye的實(shí)現(xiàn)
5淤井、縮小包體積有哪些方案币狠?
·圖片壓縮漩绵,無用圖片刪除
·一些大圖可以動態(tài)下發(fā)
·刪除無用類止吐,無用方法
·減少三方庫的依賴
計算機(jī)相關(guān)
1碍扔、項目編譯的流程是什么不同?手機(jī)上的應(yīng)用程序自點(diǎn)擊圖標(biāo)開始到首屏內(nèi)容展示都經(jīng)歷了哪些步驟?
編譯流程:
·預(yù)處理:處理宏定義溶耘,刪除注釋二拐,展開頭文件。
·詞法分析:把代碼切成一個個token汰具,比如大小括號等于號還有字符串
·語法分析:驗證語法是否正確卓鹿,合成抽象語法樹AST
·靜態(tài)分析:查找代碼錯誤
·類型檢查:動態(tài)和靜態(tài)
·目標(biāo)代碼的生成與優(yōu)化,包括刪除多余指令留荔,選擇合適的尋址方式澜倦,如果開啟了bitcode,會做進(jìn)一步的優(yōu)化
·匯編:由匯編器生成匯編語言
·機(jī)器碼:由匯編語言轉(zhuǎn)成機(jī)器碼杰妓,生成.o文件
應(yīng)用啟動的流程:
啟動的前提是完成編譯藻治,運(yùn)行程序即運(yùn)行編譯過后的目標(biāo)程序,它分為main函數(shù)前和main函數(shù)后:
main前
·加載可執(zhí)行文件(App的.o文件集合)
·加載動態(tài)鏈接庫(系統(tǒng)和應(yīng)用的動態(tài)鏈接庫)巷挥,進(jìn)行rebase指針調(diào)整和bind符號綁定
·Objc運(yùn)行時的初始處理桩卵,包括Objc相關(guān)類的注冊,category注冊倍宾,selector唯一性檢查
**·初始化雏节,包括執(zhí)行+load()、attribute(constructor)修飾的函數(shù)的調(diào)用高职、創(chuàng)建C++靜態(tài)全局變量
main后**
·首頁初始化所需要配置文件的讀寫操作
·首頁界面渲染
2钩乍、對于基本數(shù)據(jù)類型,一般是存儲到棧中的怔锌,它有沒有可能存在堆上寥粹,什么情況下會存儲到堆上?
棧和堆都是同屬一塊內(nèi)存埃元,只不過一個是高地址往低地址存儲涝涤,一個從低地址往高地址存儲,他們并沒有嚴(yán)格的界限說一個值只能放在堆上或者棧上岛杀。所以基本數(shù)據(jù)類型也是可以存儲到堆上的阔拳。
至于什么情況會存儲到堆上,我沒想到楞件,有知道的同學(xué)可以告知一下衫生。
3裳瘪、數(shù)據(jù)庫中的事務(wù)是什么意思土浸?
事務(wù)就是訪問并操作各種數(shù)據(jù)項的一個數(shù)據(jù)庫操作序列,這些操作要么全部執(zhí)行彭羹,要么全部不執(zhí)行黄伊。如果其中一個步驟出錯就要撤銷整個操作,回滾到進(jìn)入事務(wù)之前的狀態(tài)派殷。
4还最、使用過什么數(shù)據(jù)庫(我回答的Sqlite,Realm)毡惜,Realm在使用時有哪些注意事項拓轻,如何實(shí)現(xiàn)批量操作?
對于Realm感興趣的同學(xué)可以看下其官方文檔经伙。
Realm需要注意的主要就是不能直接跨線程訪問同一對象扶叉。
批量操作可以在一個單獨(dú)的事務(wù)中執(zhí)行多個數(shù)據(jù)庫的修改。
5、LRU算法是否了解枣氧,如何實(shí)現(xiàn)一套LRU算法溢十?
LRU(Least recently used 最近最少使用)算法是一個緩存淘汰算法,其作用就是當(dāng)緩存很多時达吞,該淘汰哪些內(nèi)容张弛,見名知意,它的核心思想是淘汰最近使用最少的內(nèi)容酪劫。實(shí)現(xiàn)它的關(guān)鍵步驟是:
·新數(shù)據(jù)插入到鏈表的頭部
·每當(dāng)緩存命中時吞鸭,則將數(shù)據(jù)移動到鏈表頭部
·鏈表滿時,將尾部數(shù)據(jù)清除
這個算法在SDWebImage和Kingfisher等需要處理緩存的庫中都有實(shí)現(xiàn)覆糟。
6瞒大、知道哪些設(shè)計模式,怎么理解設(shè)計模式的作用搪桂?
工廠模式透敌、觀察者模式、中介者模式踢械、單例模式酗电。這個根據(jù)實(shí)際情況說吧。
7内列、如果有1000萬個Int類型的數(shù)字撵术,如何對他們排序?
這里的隱藏含義是话瞧,內(nèi)存不夠用時如何排序嫩与,還有一個隱藏含義是硬盤足夠大。這是可以采用分而治之的方法交排,將數(shù)據(jù)分成若干塊划滋,使每一小塊滿足當(dāng)前內(nèi)容大小,然后對每塊內(nèi)容單獨(dú)排序埃篓,最后采用歸并排序?qū)λ袎K進(jìn)行排序处坪,就得到了一個有序序列。
8架专、設(shè)計一套數(shù)據(jù)庫方案同窘,實(shí)現(xiàn)類似微信的搜索關(guān)鍵詞能快速檢索出包含該字符串的聊天信息,并展示對應(yīng)數(shù)量(聊天記錄的數(shù)據(jù)量較大)
可以對聊天記錄的文本值加上索引部脚。正常情況下數(shù)據(jù)庫搜索都是全量檢索的想邦,加上索引之后只會檢索滿足條件的記錄,大大降低檢索量委刘。
簡歷相關(guān)問題
1丧没、Lottie實(shí)現(xiàn)動畫效果的原理是什么服傍?
iOS里的動畫基本都是基于CoreAnimation里的API實(shí)現(xiàn)的,Lottie也是如此骂铁。在AE上實(shí)現(xiàn)動畫效果吹零,通過插件導(dǎo)出對應(yīng)的json文件,Lottie的庫解析該json拉庵,轉(zhuǎn)成對應(yīng)的系統(tǒng)API方法灿椅。圖片的引用可以使用Base64編到j(luò)son里,也可以通過項目集成钞支,通過路徑引用茫蛹。
2、OClint實(shí)現(xiàn)靜態(tài)分析的原理是什么烁挟,它是如何做到的婴洼?
具體可以參考我之前寫的如何通過靜態(tài)分析提高iOS代碼質(zhì)量。
3撼嗓、MVVM和MVC有什么區(qū)別柬采?
對比架構(gòu)時,可以從是否職責(zé)分離且警,可測試性粉捻,可易維護(hù)性三個維度對比。
更多對比可以參考我翻譯的一篇文章:【譯】iOS 架構(gòu)模式--淺析MVC, MVP, MVVM 和 VIPER
4斑芜、靜態(tài)庫和動態(tài)庫的區(qū)別是什么肩刃?
靜態(tài)庫:鏈接時被完整復(fù)制到可執(zhí)行文件中,多次使用就多份拷貝杏头。
動態(tài)庫:鏈接時不復(fù)制盈包,而是由系統(tǒng)動態(tài)加載到內(nèi)存,內(nèi)存中只會有一份該動態(tài)庫醇王。
5呢燥、了解Flutter嗎?它有沒有使用UIKit厦画?它是如何渲染UI的疮茄?
UIKit是基于CoreAnimation渲染的,而Flutter并沒有用到它根暑,而是自己基于C++實(shí)現(xiàn)了一套渲染框架。
6徙邻、二進(jìn)制重排的核心依據(jù)是什么排嫌?
修改鏈接順序,減少啟動時的缺頁中斷缰犁。
實(shí)踐步驟可以參考李斌同學(xué)的這篇iOS 優(yōu)化篇 - 啟動優(yōu)化之Clang插樁實(shí)現(xiàn)二進(jìn)制重排
7淳地、如何設(shè)計一套切換主題的方案怖糊?
核心思路是觀察者模式+協(xié)議(通知),當(dāng)獲取到主題切換時颇象,通知各個實(shí)現(xiàn)了主題協(xié)議的類進(jìn)行更新伍伤。
8、AVPlayer和IJKPlayer有什么區(qū)別遣钳?用IJKPlayer如何實(shí)現(xiàn)一個緩存視頻列表每條視頻前1s的內(nèi)容扰魂?
因為對IJKPlayer和FFmpeg了解的不是很深,這個我也沒有確切答案蕴茴,如果有了解的小伙伴可以評論告知我劝评。
9、類似微博的短視頻列表倦淀,滑動停留播放蒋畜,如何實(shí)現(xiàn)?
這個主要就是檢測contentOffset和屏幕中間位置撞叽,設(shè)置一些邊界條件姻成,處理滑動過程中的切換行為。
10愿棋、使用python做過哪些事佣渴?如何理解腳本語言?
多語言管理初斑,csv多語言文件讀取辛润,然后寫入到項目Localizable.strings中;抓取項目中的多語言字符串见秤。
腳本(script) 其實(shí)就是一系列指令砂竖,計算機(jī)看了指令就知道自己該做什么事情。像常見的Python鹃答,Shell乎澄,Ruby都是腳本語言,他們通常不需要編譯测摔,通過解釋器運(yùn)行置济。
數(shù)據(jù)結(jié)構(gòu)與算法
1、什么是Hash表锋八,什么是Hash碰撞浙于,解決Hash碰撞有什么方法?
哈希表(Hash Table挟纱,也叫散列表)羞酗,是根據(jù)關(guān)鍵碼值 (Key-Value) 而直接進(jìn)行訪問的數(shù)據(jù)結(jié)構(gòu)。也就是說紊服,它通過把關(guān)鍵碼值映射到表中一個位置來訪問記錄檀轨,以加快查找的速度胸竞。我們常用的Dictionary就是一種Hash表。
那什么是Hash碰撞呢参萄,我們知道Hash表的查找是通過鍵值進(jìn)行定位的卫枝,當(dāng)兩個不同的輸入對應(yīng)一個輸出時,即為Hash碰撞讹挎,也被稱為Hash沖突校赤。
如果使用字典的例子你可能聯(lián)想不到?jīng)_突的情況,我們假設(shè)另一種情況:假設(shè)hash表的大小為9(即有9個槽)淤袜,現(xiàn)在要把一串?dāng)?shù)據(jù)存到表里:5,28,19,15,20,33,12,17,10痒谴。我們使用的hash函數(shù)是對9取余。這樣的話會出現(xiàn)hash(5)=5铡羡,hash(28)=1积蔚,hash(19)=1。28和19都對應(yīng)一個地址烦周,這就出現(xiàn)了Hash沖突尽爆。
解決Hash沖突的方式有開放定址法和鏈地址法。
**2读慎、如何遍歷二叉樹漱贱?
二叉樹的遍歷有三種方式,對于上面這棵二叉樹夭委,他們的遍歷結(jié)果為:
前序遍歷:根節(jié)點(diǎn) > 左子節(jié)點(diǎn) > 右子節(jié)點(diǎn)幅狮。
10潦嘶,6碳胳,4赖歌,8鸭丛,14,12揭斧,16
中序遍歷:左子節(jié)點(diǎn) > 根節(jié)點(diǎn) > 右子節(jié)點(diǎn)刚夺。
4钥屈,6屹蚊,8厕氨,10,12汹粤,14命斧,16
后序遍歷:左子節(jié)點(diǎn) > 右子節(jié)點(diǎn) > 根節(jié)點(diǎn)。
4玄括,8冯丙,6,12遭京,16胃惜,14,10
3哪雕、簡述下快速排序的過程船殉,時間復(fù)雜度是多少?
快排的思想是通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨(dú)立的兩部分斯嚎,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小利虫,然后再按此方法對這兩部分?jǐn)?shù)據(jù)分別進(jìn)行快速排序,整個排序過程可以遞歸進(jìn)行堡僻。
一個簡單的Swift實(shí)現(xiàn)方式如下:
func quicksort(_ a: [T]) -> [T] {? guard a.count > 1 else { return a }? let pivot = a[a.count/2]? let less = a.filter { $0 < pivot }? let equal = a.filter { $0 == pivot }? let greater = a.filter { $0 > pivot }? return quicksort(less) + equal + quicksort(greater)}復(fù)制代碼
快速排序是有好幾種的糠惫,他們的區(qū)別在于如何實(shí)現(xiàn)filter和分區(qū)基準(zhǔn)值的選取。
快排的時間復(fù)雜度是O(nlogn)钉疫,空間復(fù)雜度是O(logn)
4硼讽、有一個整數(shù)數(shù)組,如何只遍歷一遍就實(shí)現(xiàn)讓該數(shù)組奇數(shù)都在前面牲阁,偶數(shù)都在后面固阁?
這個是《劍指offer》里的一道題,leedcode也有對應(yīng)題目:劍指offer 21
這個相對比較簡單城菊,因為不要求有序备燃,可以采用收尾遍歷的方式,進(jìn)行交換凌唬,我這有個參考答案:
func sorted( _ nums: inout [Int]) -> [Int] {? ? guard !nums.isEmpty else {? ? ? ? return []? ? }? ? var start = 0? ? var end = nums.count - 1? ? while start < end {? ? ? ? if nums[start] % 2 != 0 {? ? ? ? ? ? start += 1? ? ? ? ? ? continue? ? ? ? }? ? ? ? if nums[end] % 2 == 0 {? ? ? ? ? ? end -= 1? ? ? ? ? ? continue? ? ? ? }? ? ? ? (nums[start], nums[end]) = (nums[end], nums[start])? ? }? ? return nums}復(fù)制代碼
5并齐、假設(shè)你正在爬樓梯。需要 n 階你才能到達(dá)樓頂客税。每次你可以爬 1 或 2 個臺階况褪。你有多少種不同的方法可以爬到樓頂呢?
leetcode 20
6霎挟、給出一個 32 位的有符號整數(shù)窝剖,你需要將這個整數(shù)中每位上的數(shù)字進(jìn)行反轉(zhuǎn)
leetcode 7
7、有紅酥夭、黃赐纱、藍(lán)三種顏色的氣球。在虐颈保客王國疙描,1個紅氣球+1個黃氣球+1個藍(lán)氣球可以兌換一張彩票
2個紅氣球+1個黃氣球可以兌換1個藍(lán)氣球。
2個黃氣球+1個藍(lán)氣球可以兌換1個紅氣球讶隐。
2個藍(lán)氣球+1個紅氣球可以兌換1個黃氣球起胰。
現(xiàn)在牛牛有a個紅氣球,b個黃氣球巫延, c個藍(lán)氣球效五,牛牛想知道自己最多可以兌換多少張彩票地消。
需要交流可以加群:(891488181)