面試題二

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ī)制

img

3、Swift和OC有什么區(qū)別齿拂?

Swift和OC的區(qū)別有很多驳规,這里簡要總結(jié)這幾條:

Swift Objective-C
語言特性 靜態(tài)語言,更加安全 動態(tài)語言署海,不那么安全
語法 更精簡 冗長
命名空間
方法調(diào)用 直接調(diào)用吗购,函數(shù)表調(diào)用,消息轉(zhuǎn)發(fā) 消息轉(zhuǎn)發(fā)
泛型/元組/高階函數(shù)
語言效率 性能更高叹侄,速度更快 略低
文件特性 .swift 單文件 .h/.m包含頭文件
編程特性 可以更好的實現(xiàn)函數(shù)式編程/響應(yīng)式編程 面向?qū)ο缶幊?/td>

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)注點和動態(tài)派發(fā)的安全性等問題琐凭。

參考喵神的面向協(xié)議編程與 Cocoa 的邂逅 (上)

OC語法

1、Block是如何實現(xiàn)的浊服?Block對應(yīng)的數(shù)據(jù)結(jié)構(gòu)是什么樣子的统屈?__block的作用是什么?它對應(yīng)的數(shù)據(jù)結(jié)構(gòu)又是什么樣子的牙躺?

block本質(zhì)是一個對象愁憔,底層用struct實現(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 指針孽拷,所有對象都有該指針吨掌,用于實現(xiàn)對象相關(guān)的功能。
  • flags脓恕,用于按 bit 位表示一些 block 的附加信息膜宋,本文后面介紹 block copy 的實現(xiàn)代碼可以看到對該變量的使用。
  • reserved炼幔,保留變量秋茫。
  • invoke,函數(shù)指針乃秀,指向具體的 block 實現(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的實現(xiàn)

2茫陆、GCD中的Block是在堆上還是棧上?

堆上擎析〔局眩可以通過block的isa指針確認(rèn)。

3、NSCoding協(xié)議是干什么用的桨醋?

一種編碼協(xié)議棚瘟,歸檔時和解檔時需要依賴該協(xié)議定義的編碼和解碼方法。Foundation和Cocoa Touch中的大部分類都遵循了這個協(xié)議喜最,一般被NSKeyedArchiver做自定義對象持久化時使用偎蘸。

4、KVO的實現(xiàn)原理

利用Runtime生成一個中間對象瞬内,讓原對象的isa指針指向它迷雪,然后重寫setter方法,插入willChangeValueForKey和didChangeValueForKey方法虫蝶。當(dāng)屬性變化時會調(diào)用振乏,會調(diào)用這兩個方法通知到外界屬性變化。

5秉扑、NSOperation有哪些特性,比著GCD有哪些優(yōu)點调限,它有哪些API舟陆?

NSOperation是對GCD的封裝,具有面向?qū)ο蟮奶攸c耻矮,可以更方便的進(jìn)行封裝秦躯,可以設(shè)置依賴關(guān)系。

API可以查看NSOperation文檔裆装。

6踱承、NSNotificaiton是同步還是異步的,如果發(fā)通知時在子線程哨免,接收在哪個線程茎活?

同步。子線程琢唾。

UI

1载荔、事件響應(yīng)鏈?zhǔn)侨绾蝹鬟f的?

手勢的點擊會發(fā)生兩個重要事情采桃,事件傳遞和事件響應(yīng)懒熙。

事件傳遞:從UIApplication開始,到window普办,再逐步往下層(子視圖)找工扎,直到找到最深層的子視圖,其為first responder衔蹲。用到的判斷方法是pointInside:withEventhitTest:withEvent肢娘。

事件響應(yīng):從識別到的視圖(first responder)開始驗證能否響應(yīng)事件,如果不能就交給其上層(父視圖)視圖,如果能相應(yīng)將不再往下傳遞蔬浙,如果直到找到UIApplication層還沒有相應(yīng)猪落,那就忽略蓋茨點擊。用到的判斷方法是touchesBegan:withEvent畴博、touchesMoved:withEvent等偶惠。

這兩個過程大致的相反的时迫。

2、什么是異步渲染?

異步渲染就是在子線程進(jìn)行繪制审葬,然后拿到主線程顯示。

UIView的顯示是通過CALayer實現(xiàn)的茶宵,CALayer的顯示則是通過contents進(jìn)行的桐汤。異步渲染的實現(xiàn)原理是當(dāng)我們改變UIView的frame時,會調(diào)用layer的setNeedsDisplay溢吻,然后調(diào)用layer的display方法维费。我們不能在非主線程將內(nèi)容繪制到layer的context上,但我們單獨開一個子線程通過CGBitmapContextCreateImage()繪制內(nèi)容促王,繪制完成之后切回主線程犀盟,將內(nèi)容賦值到contents上。

這個步驟可以參照YYText中YYTextAsyncLayer.m文件中的實現(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,那么這個過程被稱之為離屏渲染尔艇。

img

以陰影為例尔许,為什么它會導(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雖然直譯是核心動畫,但它其實是一個圖像渲染框架瓤荔,動畫實現(xiàn)只是它的一部分功能净蚤。

img

看這張圖我們可以知道,它是UIKit和AppKit的底層實現(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é)實現(xiàn)弱引用妆兑。

3魂拦、為什么當(dāng)我們在使用block時外面是weak 聲明一個weakSelf,還要在block內(nèi)部使用strong再持有一下搁嗓?

block外界聲明weak是為了實現(xiàn)block對對象的弱持有芯勘,而里面的作用是為了保證在進(jìn)到block時不會發(fā)生釋放。

4腺逛、Autoreleasepool是實現(xiàn)機(jī)制是什么荷愕?它是什么時候釋放內(nèi)部的對象的?它內(nèi)部的數(shù)據(jù)結(jié)構(gòu)是什么樣的屉来?當(dāng)我提到哨兵對象時路翻,會繼續(xù)問哨兵對象的作用是什么,為什么要設(shè)計它茄靠?

Autoreleasepool的原理是一個雙向列表茂契,它會對加入其中的對象實現(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的實現(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)用這個方法:

objc_msgSend(receiver, @selector(message))復(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ā)的時候,如果是實例方法會走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原理與實踐: 消息轉(zhuǎn)發(fā)篇(Message Forwarding) (消息機(jī)制野舶,方法未實現(xiàn)+API不兼容奔潰,模擬多繼承)

4瓦糟、category能否添加屬性筒愚,為什么赴蝇?能否添加實例變量菩浙,為什么?

可以添加屬性句伶,這里的屬性指@property劲蜻,但跟類里的@property又不一樣。正常的@property為:實例變量Ivar + Setter + Getter 方法考余,分類里的@property這三者都沒有先嬉,需要我們手動實現(xiàn)。

分類是運行時被編譯的楚堤,這時類的結(jié)構(gòu)已經(jīng)固定了疫蔓,所以我們無法添加實例變量含懊。

對于分類自定義Setter和Getter方法,我們可以通過關(guān)聯(lián)對象(Associated Object)進(jìn)行實現(xiàn)衅胀。

5岔乔、元類的作用是什么?

元類的作用是存儲類方法滚躯,同時它也是為了讓OC的類結(jié)構(gòu)能夠形成閉環(huán)雏门。

對于為甚設(shè)計元類有以下原因;

  • 在OC的世界里一切皆對象(借鑒于Smalltalk)掸掏,metaclass的設(shè)計就是要為滿足這一點茁影。
  • 在OC中Class也是一種對象,它對應(yīng)的類就是metaclass丧凤,metaclass也是一種對象募闲,它的類是root metaclass,在往上根元類(root metaclass)指向自己息裸,形成了一個閉環(huán)蝇更,一個完備的設(shè)計。
img

如果不要metaclass可不可以呼盆?也是可以的年扩,在objc_class再加一個類方法指針。但是這樣的設(shè)計會將消息傳遞的過程復(fù)雜化访圃,所以為了消息傳遞流程的復(fù)用厨幻,為了一切皆對象的思想,就有了metaclass腿时。

關(guān)于這一話題的深入討論可以參考這兩篇文章:

為什么要存在MetaClass

為什么要設(shè)計metaclass

6况脆、類方法是存儲到什么地方的?類屬性呢批糟?

類方法和類屬性都是存儲到元類中的格了。

類屬性在Swift用的多些,OC中很少有人用到徽鼎,但其實它也是有的盛末,寫法如下:

@interface Person : NSObject
// 在屬性類別中加上class
@property (class, nonatomic, copy) NSString *name;
@end
// 調(diào)用方式
NSString *temp = Person.name;復(fù)制代碼

需要注意的是跟實例屬性不一樣,類屬性不會自動生成實例變量和setter否淤,getter方法悄但,需要我們手動實現(xiàn)。具體實現(xiàn)方法可以參考這個文章:Objective-C Class Properties

7石抡、講幾個runtime的應(yīng)用場景

  • hook系統(tǒng)方法進(jìn)行方法交換檐嚣。
  • 了解一個類(閉源)的私有屬性和方法。
  • 關(guān)聯(lián)對象啰扛,實現(xiàn)添加分類屬性的功能嚎京。
  • 修改isa指針嗡贺,自定義KVO。

Runloop

1鞍帝、講一下對Runloop的理解暑刃?

Runloop就是一個運行循環(huán),它保證了在沒有任務(wù)的時候線程不退出膜眠,有任務(wù)的時候即使響應(yīng)岩臣。Runloop跟線程,事件響應(yīng)宵膨,手勢識別架谎,頁面更新,定時器都有著緊密聯(lián)系辟躏。

深入了解推薦ibireme的這篇深入理解RunLoop

2谷扣、可以用Runloop實現(xiàn)什么功能?

  • 檢測卡頓
  • 線程包活
  • 性能優(yōu)化捎琐,將一些耗時操作放到runloop wait的情況處理会涎。

性能優(yōu)化

1、對TableView進(jìn)行性能優(yōu)化有哪些方式瑞凑?

  • 緩存高度
  • 異步渲染
  • 減少離屏渲染

2末秃、Xcode的Instruments都有哪些調(diào)試的工具?

img
  • Activity Monitor(活動監(jiān)視器):監(jiān)控進(jìn)程的CPU籽御、內(nèi)存练慕、磁盤、網(wǎng)絡(luò)使用情況技掏。是程序在手機(jī)

    運行真正占用內(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,實時計算 kCFRunLoopBeforeSourceskCFRunLoopAfterWaiting 兩個狀態(tài)區(qū)域之間的耗時是否超過某個閥值
  • 子線程檢測瞄沙,每次檢測時設(shè)置標(biāo)記位為YES己沛,然后派發(fā)任務(wù)到主線程中將標(biāo)記位設(shè)置為NO。接著子線程沉睡超時闕值時長距境,判斷標(biāo)志位是否成功設(shè)置成NO申尼,如果沒有說明主線程發(fā)生了卡頓。參考ANREye的實現(xiàn)

5垫桂、縮小包體積有哪些方案师幕?

  • 圖片壓縮,無用圖片刪除
  • 一些大圖可以動態(tài)下發(fā)
  • 刪除無用類诬滩,無用方法
  • 減少三方庫的依賴

計算機(jī)相關(guān)

1霹粥、項目編譯的流程是什么?手機(jī)上的應(yīng)用程序自點擊圖標(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)用啟動的流程:

啟動的前提是完成編譯,運行程序即運行編譯過后的目標(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運行時的初始處理,包括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在使用時有哪些注意事項殃恒,如何實現(xiàn)批量操作植旧?

對于Realm感興趣的同學(xué)可以看下其官方文檔

Realm需要注意的主要就是不能直接跨線程訪問同一對象离唐。

批量操作可以在一個單獨的事務(wù)中執(zhí)行多個數(shù)據(jù)庫的修改病附。

5、LRU算法是否了解亥鬓,如何實現(xiàn)一套LRU算法完沪?

LRU(Least recently used 最近最少使用)算法是一個緩存淘汰算法,其作用就是當(dāng)緩存很多時嵌戈,該淘汰哪些內(nèi)容覆积,見名知意,它的核心思想是淘汰最近使用最少的內(nèi)容熟呛。實現(xiàn)它的關(guān)鍵步驟是:

  • 新數(shù)據(jù)插入到鏈表的頭部
  • 每當(dāng)緩存命中時宽档,則將數(shù)據(jù)移動到鏈表頭部
  • 鏈表滿時,將尾部數(shù)據(jù)清除
img

這個算法在SDWebImage和Kingfisher等需要處理緩存的庫中都有實現(xiàn)庵朝。

6吗冤、知道哪些設(shè)計模式又厉,怎么理解設(shè)計模式的作用?

工廠模式欣孤、觀察者模式、中介者模式昔逗、單例模式降传。這個根據(jù)實際情況說吧。

7勾怒、如果有1000萬個Int類型的數(shù)字婆排,如何對他們排序?

這里的隱藏含義是笔链,內(nèi)存不夠用時如何排序段只,還有一個隱藏含義是硬盤足夠大。這是可以采用分而治之的方法鉴扫,將數(shù)據(jù)分成若干塊赞枕,使每一小塊滿足當(dāng)前內(nèi)容大小,然后對每塊內(nèi)容單獨排序坪创,最后采用歸并排序?qū)λ袎K進(jìn)行排序炕婶,就得到了一個有序序列。

8莱预、設(shè)計一套數(shù)據(jù)庫方案柠掂,實現(xiàn)類似微信的搜索關(guān)鍵詞能快速檢索出包含該字符串的聊天信息,并展示對應(yīng)數(shù)量(聊天記錄的數(shù)據(jù)量較大)

可以對聊天記錄的文本值加上索引依沮。正常情況下數(shù)據(jù)庫搜索都是全量檢索的涯贞,加上索引之后只會檢索滿足條件的記錄,大大降低檢索量危喉。

簡歷相關(guān)問題

1宋渔、Lottie實現(xiàn)動畫效果的原理是什么?

iOS里的動畫基本都是基于CoreAnimation里的API實現(xiàn)的辜限,Lottie也是如此傻谁。在AE上實現(xiàn)動畫效果,通過插件導(dǎo)出對應(yīng)的json文件列粪,Lottie的庫解析該json审磁,轉(zhuǎn)成對應(yīng)的系統(tǒng)API方法。圖片的引用可以使用Base64編到j(luò)son里岂座,也可以通過項目集成态蒂,通過路徑引用。

2费什、OClint實現(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的鸟悴?

img

UIKit是基于CoreAnimation渲染的,而Flutter并沒有用到它奖年,而是自己基于C++實現(xiàn)了一套渲染框架细诸。

6、二進(jìn)制重排的核心依據(jù)是什么陋守?

修改鏈接順序震贵,減少啟動時的缺頁中斷。

實踐步驟可以參考李斌同學(xué)的這篇iOS 優(yōu)化篇 - 啟動優(yōu)化之Clang插樁實現(xiàn)二進(jìn)制重排

7水评、如何設(shè)計一套切換主題的方案猩系?

核心思路是觀察者模式+協(xié)議(通知),當(dāng)獲取到主題切換時中燥,通知各個實現(xiàn)了主題協(xié)議的類進(jìn)行更新寇甸。

8、AVPlayer和IJKPlayer有什么區(qū)別疗涉?用IJKPlayer如何實現(xiàn)一個緩存視頻列表每條視頻前1s的內(nèi)容拿霉?

因為對IJKPlayer和FFmpeg了解的不是很深,這個我也沒有確切答案咱扣,如果有了解的小伙伴可以評論告知我绽淘。

9、類似微博的短視頻列表闹伪,滑動停留播放沪铭,如何實現(xiàn)壮池?

這個主要就是檢測contentOffset和屏幕中間位置,設(shè)置一些邊界條件杀怠,處理滑動過程中的切換行為椰憋。

10、使用python做過哪些事赔退?如何理解腳本語言橙依?

多語言管理,csv多語言文件讀取离钝,然后寫入到項目Localizable.strings中票编;抓取項目中的多語言字符串褪储。

腳本(script) 其實就是一系列指令卵渴,計算機(jī)看了指令就知道自己該做什么事情。像常見的Python鲤竹,Shell浪读,Ruby都是腳本語言,他們通常不需要編譯辛藻,通過解釋器運行碘橘。

數(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桂塞、如何遍歷二叉樹凹蜂?

image-20200815112051547

二叉樹的遍歷有三種方式,對于上面這棵二叉樹阁危,他們的遍歷結(jié)果為:

前序遍歷:根節(jié)點 > 左子節(jié)點 > 右子節(jié)點玛痊。

10,6狂打,4擂煞,8,14趴乡,12对省,16

中序遍歷:左子節(jié)點 > 根節(jié)點 > 右子節(jié)點。

4晾捏,6蒿涎,8,10惦辛,12劳秋,14,16

后序遍歷:左子節(jié)點 > 右子節(jié)點 > 根節(jié)點胖齐。

4玻淑,8,6市怎,12岁忘,16,14区匠,10

3干像、簡述下快速排序的過程,時間復(fù)雜度是多少驰弄?

快排的思想是通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨立的兩部分麻汰,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小,然后再按此方法對這兩部分?jǐn)?shù)據(jù)分別進(jìn)行快速排序戚篙,整個排序過程可以遞歸進(jìn)行五鲫。

一個簡單的Swift實現(xiàn)方式如下:

func quicksort<T: Comparable>(_ 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ū)別在于如何實現(xiàn)filter和分區(qū)基準(zhǔn)值的選取岔擂。

快排的時間復(fù)雜度是O(nlogn)位喂,空間復(fù)雜度是O(logn)

4浪耘、有一個整數(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)氣球,牛牛想知道自己最多可以兌換多少張彩票宠叼。

這個是畔劝停客網(wǎng)里的一道算法題,這里有個題解可以參考冒冬。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伸蚯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子简烤,更是在濱河造成了極大的恐慌剂邮,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件横侦,死亡現(xiàn)場離奇詭異挥萌,居然都是意外死亡绰姻,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門引瀑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來龙宏,“玉大人,你說我怎么就攤上這事伤疙∫铮” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵徒像,是天一觀的道長黍特。 經(jīng)常有香客問我,道長锯蛀,這世上最難降的妖魔是什么灭衷? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮旁涤,結(jié)果婚禮上翔曲,老公的妹妹穿的比我還像新娘。我一直安慰自己劈愚,他們只是感情好瞳遍,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著菌羽,像睡著了一般掠械。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上注祖,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天猾蒂,我揣著相機(jī)與錄音,去河邊找鬼是晨。 笑死肚菠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的罩缴。 我是一名探鬼主播蚊逢,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼靴庆!你這毒婦竟也來了时捌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤炉抒,失蹤者是張志新(化名)和其女友劉穎奢讨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡拿诸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年扒袖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亩码。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡季率,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出描沟,到底是詐尸還是另有隱情飒泻,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布吏廉,位于F島的核電站泞遗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏席覆。R本人自食惡果不足惜史辙,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望佩伤。 院中可真熱鬧聊倔,春花似錦、人聲如沸生巡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽障斋。三九已至纵潦,卻和暖如春徐鹤,著一層夾襖步出監(jiān)牢的瞬間垃环,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工返敬, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留遂庄,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓劲赠,卻偏偏與公主長得像涛目,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子凛澎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容