面試題

2022面試題

1: 怎么保證自己的類一定能調(diào)用到自己寫的方法?

Category 并不會(huì)覆蓋主類的同名方法,只是Category的方法排在主類方法的前面,OC的消息發(fā)送機(jī)制是根據(jù)方法名在method_ list 中查找方法,找到第一個(gè)名字匹配的方法之后就不繼續(xù)往下找 了,每次調(diào)用的都是method. _list 中最前面的同名方法。所以我們可以根據(jù)selector查找到這個(gè)類的所有同名method,然后倒序調(diào)用,因?yàn)橹黝惖耐椒ㄔ谧詈竺妗?/p>

2: isa指針里面儲(chǔ)存了哪些信息?

nonpointer:(0)。為0表示這個(gè)isa只存儲(chǔ)了地址值,為1表示這是一個(gè)優(yōu)化過的isa。

has_assoc:(1)。記錄這個(gè)對(duì)象是否是關(guān)聯(lián)對(duì)象,沒有的話,釋放更快。

has_cxx_dtor:(2)。記錄是否有c++的析構(gòu)函數(shù),沒有的話,釋放更快。

shiftcls:(isa的第3-35位,共占33位)。記錄類對(duì)象或元類對(duì)象的地址值。

magic:(isa的第36-41位,共占6位),用于在調(diào)試時(shí)分辨對(duì)象是否完成初始化。

weakly_referenced:(42),用于記錄該對(duì)象是否被弱引用或曾經(jīng)被弱引用過,沒有被弱引用過的對(duì)象可以更快釋放。

deallocating:(43),標(biāo)志對(duì)象是否正在釋放內(nèi)存。

has_sidetable_rc:(44),用于標(biāo)記是否有擴(kuò)展的引用計(jì)數(shù)。當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)比較少時(shí),其引用計(jì)數(shù)就記錄在isa中,當(dāng)引用計(jì)數(shù)大于某個(gè)值時(shí)就會(huì)采用sideTable來協(xié)助存儲(chǔ)引用計(jì)數(shù)。

extra_rc:(isa的第45-63位,共占19位),用來記錄該對(duì)象的引用計(jì)數(shù)值-1(比如引用計(jì)數(shù)是5的話這里記錄的就是4)。這里總共是19位,如果引用計(jì)數(shù)很大,19位存不下的話就會(huì)采用sideTable來協(xié)助存儲(chǔ),規(guī)則如下:當(dāng)19位存滿時(shí),會(huì)將19位的一半(也就是上面定義的RC_HALF)存入sideTable中,如果此時(shí)引用計(jì)數(shù)又+1,那么是加在extra_rc上,當(dāng)extra_rc又存滿時(shí),繼續(xù)拿出RC_HALF的大小放入sideTable。當(dāng)引用計(jì)數(shù)減少時(shí),如果extra_rc的值減少到了0,那就從sideTable中取出RC_HALF大小放入extra_rc中。綜上所述,引用計(jì)數(shù)不管是增加還是減少都是在extra_rc上進(jìn)行的,而不會(huì)直接去操作sideTable,這是因?yàn)閟ideTable中有個(gè)自旋鎖,而引用計(jì)數(shù)的增加和減少操作是非常頻繁的,如果直接去操作sideTable會(huì)非常影響性能,所以這樣設(shè)計(jì)來盡量減少對(duì)sideTable的訪問。

3: 為什么block要用copy修飾?

1.NSConcreteGlobalBlock 全局的靜態(tài)block,不會(huì)訪問外部的變量。就是說如果你的block沒有調(diào)用其他的外部變量,那你的block類型就是這種。例如:你僅僅在你的block里面寫一個(gè)NSLog(“hello world”);

2.NSConcreteStackBlock 保存在棧中的 block,當(dāng)函數(shù)返回時(shí)會(huì)被銷毀。這個(gè)block就是你聲明的時(shí)候不用copy修飾,并且你的block訪問了外部變量。

3.NSConcreteMallocBlock 保存在堆中的block,當(dāng)引用計(jì)數(shù)為 0 時(shí)會(huì)被銷毀。好了,這個(gè)就是今天的主角 ,用copy修飾的block。

我們知道,函數(shù)的聲明周期是隨著函數(shù)調(diào)用的結(jié)束就終止了。我們的block是寫在函數(shù)中的。

如果是全局靜態(tài)block的話,他直到程序結(jié)束的時(shí)候,才會(huì)被被釋放。但是我們實(shí)際操作中基本上不會(huì)使用到不訪問外部變量的block。

如果是保存在棧中的block,他會(huì)隨著函數(shù)調(diào)用結(jié)束被銷毀。從而導(dǎo)致我們?cè)趫?zhí)行一個(gè)包含block的函數(shù)之后,就無法再訪問這個(gè)block。因?yàn)椋ê瘮?shù)結(jié)束,函數(shù)棧就銷毀了,存在函數(shù)里面的block也就沒有了),我們?cè)偈褂胋lock時(shí),就會(huì)產(chǎn)生空指針異常。

如果是堆中的block,也就是copy修飾的block。他的生命周期就是隨著對(duì)象的銷毀而結(jié)束的。只要對(duì)象不銷毀,我們就可以調(diào)用的到在堆中的block。

這就是為什么我們要用copy來修飾block。因?yàn)椴挥胏opy修飾的訪問外部變量的block,只在他所在的函數(shù)被調(diào)用的那一瞬間可以使用。之后就消失了。

使用retain也可以,但是block的retain行為默認(rèn)是用copy的行為實(shí)現(xiàn)的,

因?yàn)閎lock變量默認(rèn)是聲明為棧變量的,為了能夠在block的聲明域外使用,所以要把block拷貝(copy)到堆,所以說為了block屬性聲明和實(shí)際的操作一致,最好聲明為copy。

4: 什么是離屏渲染以及離屏渲染的影響?如何手動(dòng)觸發(fā)離屏渲染及離屏渲染使用建議

http://www.itdecent.cn/p/64cdcd52369e

離屏渲染:實(shí)現(xiàn)一些特殊效果例如圓角、陰影和遮罩、抗鋸齒、高斯模糊、半透明圖層混合等會(huì)觸發(fā)離屏渲染。,圖層屬性的混合體被指定為在未預(yù)合成之前(下一個(gè)?VSync?信號(hào)開始前)不能直接在屏幕中繪制,所以就需要屏幕外渲染被喚起。屏幕外渲染并不意味著軟件繪制,但是它意味著圖層必須在被顯示之前在一個(gè)屏幕外上下文中被渲染(不論?CPU?還是?GPU)。

影響:

1、如上圖所示相比于正常的渲染流程,離屏渲染需要額外創(chuàng)建一個(gè)離屏緩沖區(qū),需要 多耗費(fèi)一些空間;

2、觸發(fā)離屏渲染后,需要先從 Frame Buffer 切換到 Off-Screen Buffer ,渲染完畢后再切換回 Frame Buffer,這一過程需是比較 耗費(fèi)性能 的,因?yàn)橐獊砘厍袚Q上下文;

3、數(shù)據(jù)由 Off-Screen Buffer 取出,再存入 Frame Buffer 也需要 耗費(fèi)時(shí)間 ,這樣增加了 掉幀 的可能性;由于垂直同步的機(jī)制,如果在一個(gè) VSync 時(shí)間內(nèi),CPU 或者 GPU 沒有完成內(nèi)容提交,則那一幀就會(huì)被丟棄,等待下一次機(jī)會(huì)再顯示,而這時(shí)顯示屏?xí)A糁暗膬?nèi)容不變。這就是界面卡頓的原因。

4、 離屏緩沖區(qū)存在 空間限制 ,即屏幕像素的 2.5倍,當(dāng)大于這一值時(shí)便不會(huì)觸發(fā)離屏渲染。(有待擴(kuò)展相關(guān)知識(shí)面,當(dāng)需要離屏渲染時(shí)又超出離屏渲染的空間限制后,對(duì)應(yīng)超出部分會(huì)產(chǎn)生什么問題?)

如何手動(dòng)觸發(fā)離屏渲染及離屏渲染使用建議:

重點(diǎn)說說光柵化,當(dāng)設(shè)置view.layer.shouldRasterize 為 true時(shí),也會(huì)觸發(fā)離屏渲染。

光柵化概念:將圖轉(zhuǎn)化為一個(gè)個(gè)柵格組成的圖象。光柵化特點(diǎn):每個(gè)元素對(duì)應(yīng)幀緩沖區(qū)中的一像素。shouldRasterize = YES 在其他屬性觸發(fā)離屏渲染的同時(shí),會(huì)將光柵化后的內(nèi)容緩存起來,如果對(duì)應(yīng)的 layer 及其 sublayers 沒有發(fā)生改變,在下一幀的時(shí)候可以直接復(fù)用。shouldRasterize = YES 這將隱式的創(chuàng)建一個(gè)位圖,各種陰影遮罩等效果也會(huì)保存到位圖中并緩存起來,從而減少渲染的頻度。相當(dāng)于光柵化是把 GPU的操作轉(zhuǎn)到 CPU 上了,生成位圖緩存,直接讀取復(fù)用。

如果緩存的圖像在之后用不到或很少用到( 100ms內(nèi)用不到 ),則不需要開啟shouldRasterize

如果緩存的圖像會(huì)經(jīng)常發(fā)生變動(dòng),比如本身處于動(dòng)畫中,或者像tabeleView的cell的上圖片可能經(jīng)常改變,則不要開啟shouldRasterize

緩存的圖像過大,超過屏幕像素的 2.5 倍,不會(huì)觸發(fā)離屏渲染,所以開啟shouldRasterize也沒有效果.

總結(jié)

1、iOS圖形渲染流程分為 正常渲染流程 和 離屏渲染流程 ;

2、離屏渲染是在幀緩沖區(qū)之外開辟了一個(gè)臨時(shí)的緩沖區(qū),用于保存一些暫時(shí)沒有用到的數(shù)據(jù),之后會(huì)從離屏緩沖區(qū)取出,渲染后再放入幀緩沖區(qū);

3、離屏渲染會(huì)有一定的性能問題,但是我們依然會(huì)有使用到的地方;

4、離屏緩沖區(qū)最大為 屏幕像素的2.5倍 ,超出不會(huì)觸發(fā)離屏渲染;

5、設(shè)置圓角不一定會(huì)觸發(fā)離屏渲染,但是如果有 多個(gè)圖層 ,則會(huì)觸發(fā)離屏渲染。

iOS9之前UIButton、UIImageView圓角觸發(fā)離屏渲染,iOS9之后UIButton圓角觸發(fā)離屏渲染

5: 說說你對(duì)ro、rw和rwe的理解?

clean memory:是指加載后不會(huì)發(fā)生改變的內(nèi)存。class_ro_t 就屬于clean memory, 因?yàn)樗侵蛔x的(ro 代表 readonly)。

dirty memory:是指在進(jìn)程運(yùn)行時(shí)會(huì)發(fā)生更改的內(nèi)存,class_rw_t 是 dirty memory(rw 代表 read write)。

而dirty memory要比clean memory更加昂貴,前者一經(jīng)使用就必須存在,可以通過runtime往類里寫入新的數(shù)據(jù),所以dirty memory是動(dòng)態(tài)的,而clean memory是經(jīng)過編譯就不可以再寫入的,大小是固定的,是可移除的,可以節(jié)省更多的內(nèi)存空間,并且iOS是不會(huì)使用swap進(jìn)行轉(zhuǎn)換,所以dirty memory在iOS的開銷更大一些,也就是所謂的更加"昂貴"。

ro:數(shù)據(jù)是只讀的,它屬于clean Memory。它是從沙盒讀取,ro的數(shù)據(jù)在編譯的時(shí)候就已經(jīng)確定了。

rw:數(shù)據(jù)是可讀可寫的,它屬于dirty Memory。rw的數(shù)據(jù)存放的是運(yùn)行時(shí)動(dòng)態(tài)修改的數(shù)據(jù)。

rwe:是蘋果為rw做的優(yōu)化,從rw拆出來那些平時(shí)不常用的部分,以減少rw的開銷,大約 90% 的類從來不需要這些擴(kuò)展數(shù)據(jù),這在系統(tǒng)范圍內(nèi)可節(jié)省大約14MB 的內(nèi)存。

6: 蘋果為什么要設(shè)計(jì)元類?

7: 原子屬性能保障線程安全嗎?為什么?

屬性聲明為atomic時(shí),

在該屬性在調(diào)用getter和setter方法時(shí),會(huì)加上同步鎖,

即在屬性在調(diào)用getter和setter方法時(shí),保證同一時(shí)刻只能有一個(gè)線程調(diào)用屬性的讀/寫方法。

保證了讀和寫的過程是可靠的。

但并不能保證數(shù)據(jù)一定是可靠的。

線程1setterAAA

線程2setterAAA

線程1aaa

8: 如何手動(dòng)關(guān)閉 KVO?如何手動(dòng)觸發(fā) KVO?KVO的實(shí)現(xiàn)原理?

KVO原理:當(dāng)觀察一個(gè)對(duì)象時(shí),runtime會(huì)動(dòng)態(tài)創(chuàng)建繼承自該對(duì)象的類NSKVONotifying_類名,并重寫被觀察對(duì)象的setter方法,重寫的setter方法,會(huì)負(fù)責(zé)在調(diào)用原setter方法前后通知所有觀察對(duì)象值的更改,最后會(huì)把該對(duì)象的isa指針指向這個(gè)創(chuàng)建的子類,對(duì)象就變成子類的實(shí)例。

automaticallyNotifiesObserversForKey方法可以控制是否關(guān)閉屬性KVO

如何手動(dòng)觸發(fā)KVO:在setter方法里,手動(dòng)實(shí)現(xiàn)NSObject兩個(gè)方法:willChangeValueForKey、didChangeValueForKey

setValueForKey會(huì)導(dǎo)致KVO觸發(fā)

_屬性名=值;不會(huì)觸發(fā)

9: 用一句話描述GCD發(fā)生的死鎖現(xiàn)象?

主要的死鎖就是當(dāng)前串行隊(duì)列里面同步執(zhí)行當(dāng)前串行隊(duì)列。解決的方法就是將同步的串行隊(duì)列放到另外一個(gè)線程執(zhí)行。

最常用的例子,同步主線程,同步串行隊(duì)列嵌套自己

主隊(duì)列dispatch_get_main_queue串行隊(duì)列主線中執(zhí)行

全局隊(duì)列dispatch_get_global_queue并發(fā)隊(duì)列子線程中執(zhí)行

用戶隊(duì)列dispatch_queue_create串并都可以子線程中執(zhí)行

dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);

//DISPATCH_QUEUE_CONCURRENT是并行隊(duì)列

//DISPATCH_QUEUE_SERIAL是串行隊(duì)列

dispatch_sync(queue, ^{//此處無所謂同步或者異步

NSLog(@"-------->%@", [NSThread currentThread]);

dispatch_sync(queue, ^{//此處必須異步才可以,同步會(huì)導(dǎo)致崩潰

? ?????? ? ? ? ? NSLog(@"-------->%@", [NSThread currentThread]);

});

});

10: 單例的弊端?

優(yōu)點(diǎn):

1:一個(gè)類只被實(shí)例化一次,提供了對(duì)唯一實(shí)例的受控訪問。

2:節(jié)省系統(tǒng)資源

3:允許可變數(shù)目的實(shí)例。

缺點(diǎn):

1:一個(gè)類只有一個(gè)對(duì)象,可能造成責(zé)任過重,在一定程度上違背了“單一職責(zé)原則”。

2:由于單例模式中沒有抽象層,因此單例類的擴(kuò)展有很大的困難。

3:濫用單例將帶來一些負(fù)面問題,如為了節(jié)省資源將數(shù)據(jù)庫(kù)連接池對(duì)象設(shè)計(jì)為的單例類,可能會(huì)導(dǎo)致共享連接池對(duì)象的程序過多而出現(xiàn)連接池溢出;如果實(shí)例化的對(duì)象長(zhǎng)時(shí)間不被利用,系統(tǒng)會(huì)認(rèn)為是垃圾而被回收,這將導(dǎo)致對(duì)象狀態(tài)的丟失。

11: load()和initialize()的區(qū)別?

父類load

本類load

父類擴(kuò)展-load

本類擴(kuò)展-load

父類擴(kuò)展-initialize

本類擴(kuò)展-initialize

load->父類->本類->父類擴(kuò)展->本類擴(kuò)展

initialize->父類擴(kuò)展或父類->本類擴(kuò)展或本類

12: 簡(jiǎn)述APP main()函數(shù)執(zhí)行前的啟動(dòng)流程?(pass)

?????

13: runtime 如何通過 selector 找到對(duì)應(yīng)的 IMP 地址?

每一個(gè)類對(duì)象中都一個(gè)對(duì)象方法列表(對(duì)象方法緩存)

類方法列表是存放在類對(duì)象中isa指針指向的元類對(duì)象中(類方法緩存)

方法列表中每個(gè)方法結(jié)構(gòu)體中記錄著方法的名稱,方法實(shí)現(xiàn),以及參數(shù)類型,其實(shí)selector本質(zhì)就是方法名稱,通過這個(gè)方法名稱就可以在方法列表中找到對(duì)應(yīng)的方法實(shí)現(xiàn).

當(dāng)我們發(fā)送一個(gè)消息給一個(gè)NSObject對(duì)象時(shí),這條消息會(huì)在對(duì)象的類對(duì)象方法列表里查找

當(dāng)我們發(fā)送一個(gè)消息給一個(gè)類時(shí),這條消息會(huì)在類的Meta Class對(duì)象的方法列表里查找

14: 簡(jiǎn)述你對(duì)self和super的理解?

self是什么答

  1> self 是 OC 提供保留字;

  2> self 代表著當(dāng)前方法的調(diào)用者;

  3> 在 - 方法中,self代表著"對(duì)象";

  4> 在 + 方法中,self代表著"類";

  5> self 是方法的隱藏的參數(shù)變量,指向當(dāng)前調(diào)用方法的對(duì)象,另一個(gè)隱藏參數(shù)是 _cmd,代表當(dāng)前類方法的

? ? ? selector;

super是什么答

  1> super 是 OC 提供保留字;

  2> super 不是隱藏的參數(shù),它只是一個(gè)"編譯器指示符"。查找方法時(shí),指定方法查找的位置在父類;

[super init]到底做了什么答

  1> 遞歸初始化父類對(duì)象,直到root對(duì)象;

為什么把[super init]的地址賦值給self答

?????1> 整個(gè)對(duì)象過程中只有一個(gè)對(duì)象 self ,不存在父類對(duì)象的指針;

?????2> 對(duì)象內(nèi)部不管是 self 還是 super 其消息主體只有一個(gè)就是 self ,也就是說 self 和 super 指向的是同一個(gè)

?????對(duì)象;

?????3> 在父類初始化失敗的時(shí)候,返回nil,終止操作。

為什么輸出都是子類答:

  1> 參見 答4 ,結(jié)果顯而易見,self 和 super是同一個(gè)實(shí)體。

15: 簡(jiǎn)述一下dealloc的實(shí)現(xiàn)機(jī)制?

Dealloc的實(shí)現(xiàn)機(jī)制是內(nèi)容管理部分的重點(diǎn),把這個(gè)知識(shí)點(diǎn)弄明白,對(duì)于全方位的理解內(nèi)存管理的知識(shí)很有必要。

1.Dealloc 調(diào)用流程

首先調(diào)用_objc_rootDealloc()

接下來調(diào)用rootDealloc()

這時(shí)候會(huì)判斷是否可以被釋放,判斷的依據(jù)主要有 5 個(gè),判斷是否有以上五種情況

NONPointer_ISA

weakly_reference

has_assoc

has_cxx_dtor

has_sidetable_rc

如果有以上五中任意一種,將會(huì)調(diào)用object_dispose()方法,做下一步的處理

如果沒有之前五種情況的任意一種,則可以執(zhí)行釋放操作,C 函數(shù)的 free()

執(zhí)行完畢

2.object_dispose() 調(diào)用流程

直接調(diào)用objc_destructInstance()

之后調(diào)用 C 函數(shù)的 free()

3. objc_destructInstance()調(diào)用流程

先判斷hasCxxDtor,如果有 C++ 的相關(guān)內(nèi)容,要調(diào)用object_cxxDestruct(),銷毀 C++ 相關(guān)的內(nèi)容

再判斷hasAssocitatedObjects,如果有的話,要調(diào)用object_remove_associations(), 銷毀關(guān)聯(lián)對(duì)象的一系列操作

然后調(diào)用clearDeallocating()

執(zhí)行完畢

4.clearDeallocating()調(diào)用流程

先執(zhí)行sideTable_clearDellocating()

再執(zhí)行weak_clear_no_lock,在這一步驟中,會(huì)將指向該對(duì)象的弱引用指針置為nil

接下來執(zhí)行table.refcnts.eraser(),從引用計(jì)數(shù)表中擦除該對(duì)象的引用計(jì)數(shù)

16: 類簇的優(yōu)缺點(diǎn)

類簇是Foundation框架中廣泛使用的設(shè)計(jì)模式。類簇在公共抽象超類下對(duì)多個(gè)私有的具體子類進(jìn)行分組。以這種方式對(duì)類進(jìn)行分組簡(jiǎn)化了面向?qū)ο罂蚣艿墓部梢婓w系結(jié)構(gòu),而不會(huì)降低其功能豐富度。類簇是基于抽象工廠設(shè)計(jì)模式的。

優(yōu)點(diǎn):

可以將抽象基類背后的復(fù)雜細(xì)節(jié)隱藏起來。

程序員不會(huì)需要記住各種創(chuàng)建對(duì)象的具體類實(shí)現(xiàn),簡(jiǎn)化了開發(fā)成本,提高了開發(fā)效率。

便于進(jìn)行封裝和組件化。

減少了 if-else 這樣缺乏擴(kuò)展性的代碼。

增加新功能支持不影響其他代碼。

缺點(diǎn):

已有的類簇非常不好擴(kuò)展。

17: NSOperation 與 GCD 的主要區(qū)別?

1、GCD是一種輕量級(jí)的方法來實(shí)現(xiàn)多線程??刂破饋肀容^麻煩,比如取消和暫停一個(gè)線程。

2、NSOperation和NSOperationQueue相對(duì)于GCD效率上要低一點(diǎn),他們是面向?qū)ο蟮姆绞?,NSOperation底層也是用的GCD來實(shí)現(xiàn)的。可以在多個(gè)操作中添加附屬,也可以重用操作,取消或者暫停。NSOperation和KVO是兼容,也就是說,可以在NSOperation中使用KVO,例如,你可以通過NSNotificationCenter去讓一個(gè)操作開始執(zhí)行。

使用:

項(xiàng)目中使用NSOperation的優(yōu)點(diǎn)是NSOperation是對(duì)線程的高度抽象,在項(xiàng)目中使用它,會(huì)使項(xiàng)目的程序結(jié)構(gòu)更好,子類化NSOperation的設(shè)計(jì)思路,是具有面向?qū)ο蟮膬?yōu)點(diǎn)(復(fù)用,封裝),使得實(shí)現(xiàn)是多線程支持,而接口簡(jiǎn)單,建議在復(fù)雜的項(xiàng)目中使用。

項(xiàng)目中使用GCD的優(yōu)點(diǎn)是GCD本身比NSOperation簡(jiǎn)單、易用,對(duì)于不復(fù)雜的多線程操作,會(huì)節(jié)省代碼量,而Block參數(shù)的使用,會(huì)使代碼更為易讀,建議在簡(jiǎn)單的項(xiàng)目中使用

18: 介紹下App啟動(dòng)的完整過程?

(1) 系統(tǒng)為程序啟動(dòng)做好準(zhǔn)備。

(2) 系統(tǒng)將控制權(quán)交給 Dyld,Dyld 會(huì)負(fù)責(zé)后續(xù)的?作。

(3) Dyld 加載程序所需的動(dòng)態(tài)庫(kù)。

(3) Dyld 對(duì)程序進(jìn)? rebase 以及 bind 操作。

(4) Objc SetUp。

(5) 運(yùn)?初始化函數(shù)。

(6) 執(zhí)?程序的 main 函數(shù)。

19: 線程是如何切換的

20: 三次握手與四次揮手

(1)首先客戶端向服務(wù)器端發(fā)送一段TCP報(bào)文,其中:

標(biāo)記位為SYN,表示“請(qǐng)求建立新連接”;

序號(hào)為Seq=X(X一般為1);

隨后客戶端進(jìn)入SYN-SENT階段。

(2)服務(wù)器端接收到來自客戶端的TCP報(bào)文之后,結(jié)束LISTEN階段。并返回一段TCP報(bào)文,其中:

標(biāo)志位為SYN和ACK,表示“確認(rèn)客戶端的報(bào)文Seq序號(hào)有效,服務(wù)器能正常接收客戶端發(fā)送的數(shù)據(jù),并同意創(chuàng)建新連接”(即告訴客戶端,服務(wù)器收到了你的數(shù)據(jù));

序號(hào)為Seq=y;

確認(rèn)號(hào)為Ack=x+1,表示收到客戶端的序號(hào)Seq并將其值加1作為自己確認(rèn)號(hào)Ack的值;隨后服務(wù)器端進(jìn)入SYN-RCVD階段。

(3)客戶端接收到來自服務(wù)器端的確認(rèn)收到數(shù)據(jù)的TCP報(bào)文之后,明確了從客戶端到服務(wù)器的數(shù)據(jù)傳輸是正常的,結(jié)束SYN-SENT階段。并返回最后一段TCP報(bào)文。其中:

標(biāo)志位為ACK,表示“確認(rèn)收到服務(wù)器端同意連接的信號(hào)”(即告訴服務(wù)器,我知道你收到我發(fā)的數(shù)據(jù)了);

序號(hào)為Seq=x+1,表示收到服務(wù)器端的確認(rèn)號(hào)Ack,并將其值作為自己的序號(hào)值;

確認(rèn)號(hào)為Ack=y+1,表示收到服務(wù)器端序號(hào)Seq,并將其值加1作為自己的確認(rèn)號(hào)Ack的值;

隨后客戶端進(jìn)入ESTABLISHED階段。

服務(wù)器收到來自客戶端的“確認(rèn)收到服務(wù)器數(shù)據(jù)”的TCP報(bào)文之后,明確了從服務(wù)器到客戶端的數(shù)據(jù)傳輸是正常的。結(jié)束SYN-SENT階段,進(jìn)入ESTABLISHED階段。

在客戶端與服務(wù)器端傳輸?shù)腡CP報(bào)文中,雙方的確認(rèn)號(hào)Ack和序號(hào)Seq的值,都是在彼此Ack和Seq值的基礎(chǔ)上進(jìn)行計(jì)算的,這樣做保證了TCP報(bào)文傳輸?shù)倪B貫性。一旦出現(xiàn)某一方發(fā)出的TCP報(bào)文丟失,便無法繼續(xù)"握手",以此確保了"三次握手"的順利完成。

此后客戶端和服務(wù)器端進(jìn)行正常的數(shù)據(jù)傳輸。這就是“三次握手”的過程。

(1)首先客戶端想要釋放連接,向服務(wù)器端發(fā)送一段TCP報(bào)文,其中:

標(biāo)記位為FIN,表示“請(qǐng)求釋放連接“;

序號(hào)為Seq=U;

隨后客戶端進(jìn)入FIN-WAIT-1階段,即半關(guān)閉階段。并且停止在客戶端到服務(wù)器端方向上發(fā)送數(shù)據(jù),但是客戶端仍然能接收從服務(wù)器端傳輸過來的數(shù)據(jù)。

注意:這里不發(fā)送的是正常連接時(shí)傳輸?shù)臄?shù)據(jù)(非確認(rèn)報(bào)文),而不是一切數(shù)據(jù),所以客戶端仍然能發(fā)送ACK確認(rèn)報(bào)文。

(2)服務(wù)器端接收到從客戶端發(fā)出的TCP報(bào)文之后,確認(rèn)了客戶端想要釋放連接,隨后服務(wù)器端結(jié)束ESTABLISHED階段,進(jìn)入CLOSE-WAIT階段(半關(guān)閉狀態(tài))并返回一段TCP報(bào)文,其中:

標(biāo)記位為ACK,表示“接收到客戶端發(fā)送的釋放連接的請(qǐng)求”;

序號(hào)為Seq=V;

確認(rèn)號(hào)為Ack=U+1,表示是在收到客戶端報(bào)文的基礎(chǔ)上,將其序號(hào)Seq值加1作為本段報(bào)文確認(rèn)號(hào)Ack的值;

隨后服務(wù)器端開始準(zhǔn)備釋放服務(wù)器端到客戶端方向上的連接。

客戶端收到從服務(wù)器端發(fā)出的TCP報(bào)文之后,確認(rèn)了服務(wù)器收到了客戶端發(fā)出的釋放連接請(qǐng)求,隨后客戶端結(jié)束FIN-WAIT-1階段,進(jìn)入FIN-WAIT-2階段

前"兩次揮手"既讓服務(wù)器端知道了客戶端想要釋放連接,也讓客戶端知道了服務(wù)器端了解了自己想要釋放連接的請(qǐng)求。于是,可以確認(rèn)關(guān)閉客戶端到服務(wù)器端方向上的連接了

(3)服務(wù)器端自從發(fā)出ACK確認(rèn)報(bào)文之后,經(jīng)過CLOSED-WAIT階段,做好了釋放服務(wù)器端到客戶端方向上的連接準(zhǔn)備,再次向客戶端發(fā)出一段TCP報(bào)文,其中:

標(biāo)記位為FIN,ACK,表示“已經(jīng)準(zhǔn)備好釋放連接了”。注意:這里的ACK并不是確認(rèn)收到服務(wù)器端報(bào)文的確認(rèn)報(bào)文。

序號(hào)為Seq=W;

確認(rèn)號(hào)為Ack=U+1;表示是在收到客戶端報(bào)文的基礎(chǔ)上,將其序號(hào)Seq值加1作為本段報(bào)文確認(rèn)號(hào)Ack的值。

隨后服務(wù)器端結(jié)束CLOSE-WAIT階段,進(jìn)入LAST-ACK階段。并且停止在服務(wù)器端到客戶端的方向上發(fā)送數(shù)據(jù),但是服務(wù)器端仍然能夠接收從客戶端傳輸過來的數(shù)據(jù)。

(4)客戶端收到從服務(wù)器端發(fā)出的TCP報(bào)文,確認(rèn)了服務(wù)器端已做好釋放連接的準(zhǔn)備,結(jié)束FIN-WAIT-2階段,進(jìn)入TIME-WAIT階段,并向服務(wù)器端發(fā)送一段報(bào)文,其中:

標(biāo)記位為ACK,表示“接收到服務(wù)器準(zhǔn)備好釋放連接的信號(hào)”。

序號(hào)為Seq=U+1;表示是在收到了服務(wù)器端報(bào)文的基礎(chǔ)上,將其確認(rèn)號(hào)Ack值作為本段報(bào)文序號(hào)的值。

確認(rèn)號(hào)為Ack=W+1;表示是在收到了服務(wù)器端報(bào)文的基礎(chǔ)上,將其序號(hào)Seq值作為本段報(bào)文確認(rèn)號(hào)的值。

隨后客戶端開始在TIME-WAIT階段等待2MSL

21: 怎么防止反編譯?

1、內(nèi)購(gòu)破解

iOS應(yīng)用需防反編譯風(fēng)險(xiǎn)之一:插件法(僅越獄)、iTools工具替換文件法(常見為存檔破解)、八門神器修改

2、網(wǎng)絡(luò)安全風(fēng)險(xiǎn)

iOS應(yīng)用需防反編譯風(fēng)險(xiǎn)之二:截獲網(wǎng)絡(luò)請(qǐng)求,破解通信協(xié)議并模擬客戶端登錄,偽造用戶行為,對(duì)用戶數(shù)據(jù)造成危害

3、應(yīng)用程序函數(shù)PATCH破解

iOS應(yīng)用需防反編譯風(fēng)險(xiǎn)之三:利用FLEX 補(bǔ)丁軟件通過派遣返回值來對(duì)應(yīng)用進(jìn)行patch破解

4、源代碼安全風(fēng)險(xiǎn)

iOS應(yīng)用需防反編譯風(fēng)險(xiǎn)之四:通過使用ida等反匯編工具對(duì)ipa進(jìn)行逆向匯編代碼,導(dǎo)致核心代碼邏輯泄漏與被修改,影響應(yīng)用安全

1、本地?cái)?shù)據(jù)加密

iOS應(yīng)用防反編譯加密技術(shù)之一:對(duì)NSUserDefaults,sqlite存儲(chǔ)文件數(shù)據(jù)加密,保護(hù)帳號(hào)和關(guān)鍵信息

2、URL編碼加密

iOS應(yīng)用防反編譯加密技術(shù)之二:對(duì)程序中出現(xiàn)的URL進(jìn)行編碼加密,防止URL被靜態(tài)分析

3、網(wǎng)絡(luò)傳輸數(shù)據(jù)加密

iOS應(yīng)用防反編譯加密技術(shù)之三:對(duì)客戶端傳輸數(shù)據(jù)提供加密方案,有效防止通過網(wǎng)絡(luò)接口的攔截獲取數(shù)據(jù)

4、方法體,方法名高級(jí)混淆

iOS應(yīng)用防反編譯加密技術(shù)之四:對(duì)應(yīng)用程序的方法名和方法體進(jìn)行混淆,保證源碼被逆向后無法解析代碼

5、程序結(jié)構(gòu)混排加密

iOS應(yīng)用防反編譯加密技術(shù)之五:對(duì)應(yīng)用程序邏輯結(jié)構(gòu)進(jìn)行打亂混排,保證源碼可讀性降到最低

22: 為什么CTMediator方案優(yōu)于基于Router的方案?


23: 斷點(diǎn)續(xù)傳如何實(shí)現(xiàn)的?

1.斷點(diǎn)續(xù)傳需要在下載過程中記錄每條線程的下載進(jìn)度;

2.每次下載開始之前先讀取數(shù)據(jù)庫(kù),查詢是否有未完成的記錄,有就繼續(xù)下載,沒有則創(chuàng)建新記錄插入數(shù)據(jù)庫(kù);

3.在每次向文件中寫入數(shù)據(jù)之后,在數(shù)據(jù)庫(kù)中更新下載進(jìn)度;

4.下載完成之后刪除數(shù)據(jù)庫(kù)中下載記錄。

24: JS有沒有用過,原理是什么?


25: 簡(jiǎn)述組件化實(shí)現(xiàn)過程

http://www.itdecent.cn/p/012a9d2f98bb

組件化的幾種方法

第一種url-block方式:

頁面間調(diào)用的方式,通過在啟動(dòng)時(shí)注冊(cè)組件提供的服務(wù),把調(diào)用組件使用的url和組件提供的服務(wù)block對(duì)應(yīng)起來,保存到內(nèi)存中。在使用組件的服務(wù)時(shí),通過url找到對(duì)應(yīng)的block,然后獲取服務(wù)。

需要在內(nèi)存中維護(hù)url-block的表,組件多了可能會(huì)有內(nèi)存問題

url的參數(shù)傳遞受到限制,只能傳遞常規(guī)的字符串參數(shù),無法傳遞非常規(guī)參數(shù),如UIImage、NSData等類型

沒有區(qū)分本地調(diào)用和遠(yuǎn)程調(diào)用的情況,尤其是遠(yuǎn)程調(diào)用,會(huì)因?yàn)閡rl參數(shù)受限,導(dǎo)致一些功能受限

組件本身依賴了中間件,且分散注冊(cè)使的耦合較多

第二種protocol-class方式:

第三種url-controller方式:

這部分我將其分為兩類:一類是公共基礎(chǔ)庫(kù),用于跨產(chǎn)品使用;一類是產(chǎn)品基礎(chǔ)庫(kù),在某個(gè)產(chǎn)品中強(qiáng)相關(guān)依賴使用。這里以我們自己產(chǎn)品劃分為例,概述一下這兩類庫(kù)都包括哪些基礎(chǔ)組件:

公共庫(kù)包括:組件化中間件、網(wǎng)絡(luò)診斷、第三方SDK管理封裝、長(zhǎng)連接相關(guān)、Patch相關(guān)、網(wǎng)絡(luò)和頁面監(jiān)控相關(guān)、用戶行為統(tǒng)計(jì)庫(kù)、第三方分享庫(kù)、JSBridge相關(guān)、關(guān)于Device+file+crypt+http的基礎(chǔ)方法等。

產(chǎn)品基礎(chǔ)庫(kù)包括:通用的WebViewContainer組件(封裝了JSBridge)、自定義數(shù)字鍵盤、表情鍵盤、自定義下拉列表、循環(huán)滾動(dòng)頁面、AFNeworking封裝庫(kù)(對(duì)上層業(yè)務(wù)隱藏AF的直接引用)、以及其他自定義的UI基礎(chǔ)組件庫(kù)。

第四種target-action方式

26: 分類的底層是怎么實(shí)現(xiàn)的?

通過Runtime加載某個(gè)類的所有Category數(shù)據(jù);

把所有Category的方法、屬性、協(xié)議數(shù)據(jù),合并到一個(gè)大數(shù)組中,后面參與編譯的Category數(shù)據(jù),會(huì)在數(shù)組的前面。

將合并后的Category分類數(shù)據(jù)(方法、屬性、協(xié)議),插入到存放類(類對(duì)象、元類對(duì)象)原來數(shù)據(jù)的數(shù)組前面。

由于Category分類的數(shù)據(jù)(方法、屬性、協(xié)議)在類數(shù)據(jù)數(shù)組的最前面,所以當(dāng)調(diào)用原類、Category(分類)中同名的方法時(shí),會(huì)優(yōu)先調(diào)用Category(分類)中的方法,從而實(shí)現(xiàn)覆蓋了類原本的方法。

分類添加屬性原理:

setter方法objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);

getter方法objc_getAssociatedObject(self, _cmd);

27: 如何監(jiān)控線上版本APP啟動(dòng)耗時(shí)(包含動(dòng)態(tài)庫(kù)的加載時(shí)間)

1、main() 函數(shù)執(zhí)行前;

在 main() 函數(shù)執(zhí)行前,系統(tǒng)主要會(huì)做下面幾件事情:

加載可執(zhí)行文件(App 的.o 文件的集合);

加載動(dòng)態(tài)鏈接庫(kù),進(jìn)行 rebase 指針調(diào)整和 bind 符號(hào)綁定;

Objc 運(yùn)行時(shí)的初始處理,包括 Objc 相關(guān)類的注冊(cè)、category 注冊(cè)、selector 唯一性檢查等;

初始化,包括了執(zhí)行 +load() 方法、attribute((constructor)) 修飾的函數(shù)的調(diào)用、創(chuàng)建 C++ 靜態(tài)全局變量。

2、main() 函數(shù)執(zhí)行后;

很多時(shí)候,開發(fā)者會(huì)把各種初始化工作都放到這個(gè)階段執(zhí)行,導(dǎo)致渲染完成滯后。更加優(yōu)化的開發(fā)方式,應(yīng)該是從功能上梳理出哪些是首屏渲染必要的初始化功能,哪些是 App 啟動(dòng)必要的初始化功能,而哪些是只需要在對(duì)應(yīng)功能開始使用時(shí)才需要初始化的。梳理完之后,將這些初始化功能分別放到合適的階段進(jìn)行。

3、首屏渲染完成后。

28: 如何優(yōu)化 App 的啟動(dòng)耗時(shí)?

pre-main()

1. 動(dòng)態(tài)庫(kù)加載越多,啟動(dòng)越慢

2. ObjC類,方法越多,啟動(dòng)越慢

3. ObjC的+load越多,啟動(dòng)越慢

4. C的constructor函數(shù)越多,啟動(dòng)越慢

5. C++靜態(tài)對(duì)象越多,啟動(dòng)越慢

main()之后

appdelegate的didFinishLaunchingWithOptions初始化可以異步加載盡量使用異步避免阻塞主線程

首屏初始化所需配置文件的讀寫操作;

首屏列表大數(shù)據(jù)的讀?。?/p>

首屏渲染的大量計(jì)算等。

29: 動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)的區(qū)別?為什么動(dòng)態(tài)庫(kù)會(huì)影響啟動(dòng)速度?

? ? ?靜態(tài)庫(kù)編譯加載到可執(zhí)行文件程序啟動(dòng)時(shí)直接加載,動(dòng)態(tài)庫(kù)是在啟動(dòng)時(shí)動(dòng)態(tài)鏈接.

? ? ?靜態(tài)庫(kù)冷啟動(dòng)速度快,動(dòng)態(tài)庫(kù)冷啟動(dòng)速度慢(啟動(dòng)時(shí)動(dòng)態(tài)鏈接)優(yōu)化方式冷加載。


30: 使用drawRect有什么影響?

缺點(diǎn):它處理touch事件時(shí)每次按鈕被點(diǎn)擊后,都會(huì)用setNeddsDisplay進(jìn)行強(qiáng)制重繪;而且不止一次,每次單點(diǎn)事件觸發(fā)兩次執(zhí)行。這樣的話從性能的角度來說,對(duì)CPU和內(nèi)存來說都是欠佳的。特別是如果在我們的界面上有多個(gè)這樣的UIButton實(shí)例,那就會(huì)很糟糕了

這個(gè)方法的調(diào)用機(jī)制也是非常特別. 當(dāng)你調(diào)用 setNeedsDisplay 方法時(shí), UIKit 將會(huì)把當(dāng)前圖層標(biāo)記為dirty,但還是會(huì)顯示原來的內(nèi)容,直到下一次的視圖渲染周期,才會(huì)將標(biāo)記為 dirty 的圖層重新建立Core Graphics上下文,然后將內(nèi)存中的數(shù)據(jù)恢復(fù)出來, 再使用 CGContextRef 進(jìn)行繪制

31: 自動(dòng)釋放池的原理?

自動(dòng)釋放池(autorelease pool)是一種內(nèi)存自動(dòng)回收機(jī)制。

引用計(jì)數(shù):

-當(dāng)我們創(chuàng)建一個(gè)實(shí)例對(duì)象,它的引用計(jì)數(shù)為1;

-當(dāng)我們向一個(gè)對(duì)象發(fā)送retain消息,它的引用計(jì)數(shù)+1;

-當(dāng)我們向一個(gè)對(duì)象發(fā)送release消息,它的引用計(jì)數(shù)-1;

-當(dāng)我們向一個(gè)對(duì)象發(fā)送autorelease消息,它的引用計(jì)數(shù)會(huì)在當(dāng)前自動(dòng)釋放池的末尾-1;

-當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)減到0,它的內(nèi)存會(huì)被回收。

哨兵模式,只要調(diào)用autorelease方法,就會(huì)把該對(duì)象放到離自己最近的自動(dòng)釋放池中(棧頂?shù)尼尫懦兀?。在引用?jì)數(shù)變成0的時(shí)候,runloop會(huì)把對(duì)象銷毀。

release (不考慮其他情況),引用計(jì)數(shù)變成0,runloop會(huì)把對(duì)象銷毀。

32: UITableView重用機(jī)制原理?

UITableView 有緩存池,在創(chuàng)建 UITableViewCell 的時(shí)候,會(huì)根據(jù) cellId 先去緩存池里面去查有沒有這個(gè) cell, 有的話直接拿出來用,沒有再創(chuàng)建。

當(dāng) cell 離開屏幕的可視范圍后,就會(huì)被父視圖 remove 掉,進(jìn)入緩存池,長(zhǎng)時(shí)間沒被使用的話,會(huì)被銷毀。

33: 線程保活有幾種方式?

1、[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];

2、

34: 怎樣監(jiān)測(cè)卡頓問題?監(jiān)測(cè)到之后怎樣優(yōu)化?


36: 實(shí)際開發(fā)MVC存在什么問題?面向協(xié)議編程的MVP架構(gòu)思想、雙向綁定MVVM的架構(gòu)思想


37: loadView

作用:

loadView方法就是用來創(chuàng)建UIViewController的View的

什么時(shí)候被調(diào)用:

首次訪問UIViewController的view(如:viewController.view或self.view),而且view為nil,loadView方法就會(huì)被調(diào)用

實(shí)現(xiàn)機(jī)制:

如果當(dāng)前控制器不實(shí)現(xiàn)loadView方法,會(huì)默認(rèn)調(diào)用父類的loadView方法。默認(rèn)系統(tǒng)加載:先去storyboard里找,若沒有找到,再去與控制器名稱相同的xib里找,如果還沒找到,那么系統(tǒng)就會(huì)默認(rèn)創(chuàng)建一個(gè)空白的view當(dāng)作是控制器的view,顏色是clearColor

如果當(dāng)前控制器實(shí)現(xiàn)了loadView方法,那么上面的都不會(huì)做,所以重寫loadView方法不需要調(diào)用super,節(jié)省不必要的開銷。

38:copy和strong的區(qū)別

1> 當(dāng)源字符串是NSString時(shí),由于是不可變字符串,所以不管是實(shí)用strong還是copy修飾,都是指向原來的對(duì)象,copy只是做了一次淺拷貝。

2> 當(dāng)源字符串是NSMutableString時(shí),strong只是將源字符串的引用計(jì)數(shù)+1,而copy則是對(duì)源字符串做了次深拷貝,從而生成了一個(gè)新的對(duì)象,并且copy的對(duì)象指向這個(gè)新對(duì)象。

所以,如果源字符串是NSMutableString時(shí),實(shí)用strong只會(huì)增加引用計(jì)數(shù),但copy會(huì)執(zhí)行一次深拷貝,會(huì)造成不必要的內(nèi)存浪費(fèi)。而如果源字符串是NSString時(shí),strong和copy效果一樣,就不會(huì)有這個(gè)問題。

我們一般聲明NSString時(shí),也不希望它改變,所以一般情況下,建議使用copy,這樣可以避免NSMutableString帶來的錯(cuò)誤。

39:『iOS』引用計(jì)數(shù)是存放在哪里?

ARM64之前,對(duì)象的引用計(jì)數(shù)都存儲(chǔ)在一個(gè)叫SideTable結(jié)構(gòu)體的RefCountMap(引用計(jì)數(shù)表)散列表中;

ARM64之后是保存在ISA中。

詳見:http://www.itdecent.cn/p/43571ab79821

40:組件化的方案,有什么異同點(diǎn)?

目前業(yè)界有三大通用方案:面向接口進(jìn)行解耦、使用URL路由的方式以及使用runtime進(jìn)行解耦。各自的代表為:serviceCenter注冊(cè)的BeeHive、URL注冊(cè)的Router、使用runtime+Category的CTMediator (https://blog.csdn.net/songzhuo1991/article/details/115977726)

BeeHive: Protcol-impclass 的方式,service層為各個(gè)模塊對(duì)外提供的接口采用protocol的方式,而implclass 為具體實(shí)現(xiàn)的類,所有組件會(huì)依賴中間層,由中間層統(tǒng)一對(duì)外暴露模塊的服務(wù);(http://www.itdecent.cn/p/4de4c7cb8ad9)

Router: URLRouter方式,采用字符串硬編碼方式,通過路由協(xié)議來服務(wù);一般現(xiàn)在多用于頁面跳轉(zhuǎn)的路由。

CTMediator: target-Action方式,充分利用runtime特性,分本地和遠(yuǎn)程調(diào)用。外部調(diào)用:約定好URL規(guī)則之后,將遠(yuǎn)程調(diào)度在內(nèi)部轉(zhuǎn)為本地調(diào)度。本地調(diào)度:需要按照規(guī)則創(chuàng)建Target-Action提供模塊的服務(wù)。利用CTMediator分類方式明確了對(duì)外提供接口,使用runtime主動(dòng)發(fā)現(xiàn)服務(wù)方后在利用invocation進(jìn)行方法的調(diào)用。(https://blog.csdn.net/songzhuo1991/article/details/115977726)

41、@property 的本質(zhì)是什么?ivar、getter、setter 是如何生成并添加到這個(gè)類中的

@property = ivar + getter + setter;

“屬性” (property)有兩大概念:ivar(實(shí)例變量)、getter+setter(存取方法)

“屬性” (property)作為 Objective-C 的一項(xiàng)特性,主要的作用就在于封裝對(duì)象中的數(shù)據(jù)。 Objective-C 對(duì)象通常會(huì)把其所需要的數(shù)據(jù)保存為各種實(shí)例變量。實(shí)例變量一般通過“存取方法”(access method)來訪問。其中,“獲取方法” (getter)用于讀取變量值,而“設(shè)置方法” (setter)用于寫入變量值。

42、@synthesize 和 @dynamic 分別有什么作用?

@property有兩個(gè)對(duì)應(yīng)的詞,一個(gè)是@synthesize(合成實(shí)例變量),一個(gè)是@dynamic。

如果@synthesize和@dynamic都沒有寫,那么默認(rèn)的就是 @synthesize var = _var;

// 在類的實(shí)現(xiàn)代碼里通過 @synthesize 語法可以來指定實(shí)例變量的名字。(@synthesize var = _newVar;)

1. @synthesize 的語義是如果你沒有手動(dòng)實(shí)現(xiàn)setter方法和getter方法,那么編譯器會(huì)自動(dòng)為你加上這兩個(gè)方法。

2. @dynamic 告訴編譯器,屬性的setter與getter方法由用戶自己實(shí)現(xiàn),不自動(dòng)生成(如,@dynamic var)。

43、KVC的底層實(shí)現(xiàn)?

setValue: forKey: valueForKey:

當(dāng)一個(gè)對(duì)象調(diào)用setValue方法時(shí),方法內(nèi)部會(huì)做以下操作:

1). 檢查是否存在相應(yīng)的key的set方法,如果存在,就調(diào)用set方法。

2). 如果set方法不存在,就會(huì)查找與key相同名稱并且?guī)聞澗€的成員變量,如果有,則直接給成員變量屬性賦值。

3). 如果沒有找到_key,就會(huì)查找相同名稱的屬性key,如果有就直接賦值。

4). 如果還沒有找到,則調(diào)用valueForUndefinedKey:和setValue:forUndefinedKey:方法。

這些方法的默認(rèn)實(shí)現(xiàn)都是拋出異常,我們可以根據(jù)需要重寫它們。

44、KVO的底層實(shí)現(xiàn)?

當(dāng)某個(gè)類的屬性對(duì)象第一次被觀察時(shí),系統(tǒng)就會(huì)在運(yùn)行期間動(dòng)態(tài)地創(chuàng)建該類的一個(gè)派生類,在這個(gè)派生類中重寫基類的任何被 觀察屬性的setter方法。派生類在被重寫的setter方法內(nèi)實(shí)現(xiàn)真正的通知機(jī)制

如果原類為Person,那么生成的派生類名為NSKVONotifying_Person

我們知道,每一個(gè)類中都有一個(gè)isa指針指向當(dāng)前類,所有系統(tǒng)就是在當(dāng)一個(gè)類的對(duì)象第一次被觀察的時(shí)候,系統(tǒng)就會(huì)偷偷將 isa指針指向動(dòng)態(tài)生成的派生類,從而在被監(jiān)聽屬性賦值時(shí)被執(zhí)行的是派生類的setter方法

willChangeValueForKey: 和 didChangevalueForKey:

automaticallyNotifiesObserversForKey可以返回NO設(shè)置某些屬性不被監(jiān)聽

45、如何訪問并修改一個(gè)類的私有屬性?

1). 一種是通過KVC獲取。

setvalueforkey/valueforkey

2). 通過runtime訪問并修改私有屬性。

46、delegate 和 notification 的區(qū)別

1). 二者都用于傳遞消息,不同之處主要在于一個(gè)是一對(duì)一的,另一個(gè)是一對(duì)多的。

2). notification通過維護(hù)一個(gè)array,實(shí)現(xiàn)一對(duì)多消息的轉(zhuǎn)發(fā)。

3). delegate需要兩者之間必須建立聯(lián)系,不然沒法調(diào)用代理的方法;notification不需要兩者之間有聯(lián)系。

47、什么是block

block是將函數(shù)及其執(zhí)行上下文封裝起來的對(duì)象。

block內(nèi)部有isa指針,所以說其本質(zhì)也是OC對(duì)象

參考鏈接http://www.itdecent.cn/p/08235d740480

struct?__block_impl?{

? void?*isa;//isa指針,所以說Block是對(duì)象

? int?Flags;

? int?Reserved;

? void?*FuncPtr;//函數(shù)指針

};

48、你一般是怎么用Instruments的?

Instruments里面工具很多,常用:

1). Time Profiler: 性能分析

2). Zombies:檢查是否訪問了僵尸對(duì)象,但是這個(gè)工具只能從上往下檢查,不智能。

3). Allocations:用來檢查內(nèi)存,寫算法的那批人也用這個(gè)來檢查。

4). Leaks:檢查內(nèi)存,看是否有內(nèi)存泄露。

49、iOS中常用的數(shù)據(jù)存儲(chǔ)方式有哪些?

數(shù)據(jù)存儲(chǔ)有四種方案:

NSUserDefault、KeyChain、file、DB。?

其中File有三種方式:plist、Archive(歸檔)?

DB包括:SQLite、FMDB、CoreData、WCDB(微信)

WCDB 是騰訊開源的一個(gè)高效、完整、易用的移動(dòng)數(shù)據(jù)庫(kù)框架,基于SQLCipher,支持 iOS、macOS 和 Android。

基本功能

WINQ(WCDB語言集成查詢): 通過WINQ,開發(fā)者無須為了拼接SQL的字符串而寫一大坨膠水代碼。

ORM(Object Relational Mapping): WCDB支持靈活、易用的ORM。開發(fā)者可以很便捷地定義表、索引、約束,并進(jìn)行增刪改查操作。

多線程高并發(fā): WCDB支持多線程讀與讀、讀與寫并發(fā)執(zhí)行,寫與寫串行執(zhí)行。

加密:WCDB提供基于SQLCipher的數(shù)據(jù)庫(kù)加密。

損壞修復(fù): WCDB內(nèi)建了Repair Kit用于修復(fù)損壞的數(shù)據(jù)庫(kù)。

反注入: WCDB內(nèi)建了對(duì)SQL注入的保護(hù)。

50、怎么處理等待幾個(gè)任務(wù)執(zhí)行完成才開始下一步任務(wù)

1、使用GCD的dispatch_group,enter和leave,然后使用group的notify執(zhí)行

2、使用GCD的信號(hào)量,注意在子線程中進(jìn)行signal,wait-1和signal+1搭配,大于等于0執(zhí)行

3、使用柵欄函數(shù)barrier,注意這里指定給barrier添加的并發(fā)隊(duì)列應(yīng)該是自己通過dispatch_queue_create函數(shù)創(chuàng)建的,如果傳的是一個(gè)串行隊(duì)列或者全局并發(fā)隊(duì)列,那此時(shí)dispatch_barrier等同于Dispatch_async。

51、如何高性能的給 UIImageView 加個(gè)圓角?

不好的解決方案:使用下面的方式會(huì)強(qiáng)制Core Animation提前渲染屏幕的離屏繪制, 而離屏繪制就會(huì)給性能帶來負(fù)面影響,會(huì)有卡頓的現(xiàn)象出現(xiàn)。

self.view.layer.cornerRadius =5.0f;

self.view.layer.masksToBounds =YES;

正確的解決方案:使用畫布core graphics的AddEllipseInRect

還有一種方案:使用了貝塞爾曲線"切割"這個(gè)圖片addClip

52、HTTP協(xié)議中 POST 方法和 GET 方法有那些區(qū)別?

1. GET用于向服務(wù)器請(qǐng)求數(shù)據(jù),POST用于提交數(shù)據(jù)

2. GET請(qǐng)求,請(qǐng)求參數(shù)拼接形式暴露在地址欄,而POST請(qǐng)求參數(shù)則放在請(qǐng)求體里面

3. GET請(qǐng)求的URL有長(zhǎng)度限制,POST請(qǐng)求不會(huì)有長(zhǎng)度限制

53、native和hybrid理解

native即是原生APP開發(fā)

hybrid混合開發(fā)

web就是網(wǎng)頁 pc端的網(wǎng)頁 移動(dòng)端的網(wǎng)頁 輸入域名就可以看見界面

native app 原生態(tài)app 就是我們常見的app 代碼都是用java(安卓) swift/object-c(蘋果)寫的

hybrid 混合的 上面兩種混合起來 比如安卓,你做好web界面 直接用 webview直接加載web界面,就不用 用native app一個(gè)個(gè)界面布局 簡(jiǎn)單快速方便

54、點(diǎn)擊屏幕后發(fā)生了什么?

首先,以下三種情況下UIView不接受觸摸事件:

1.userInteractionEnabled = NO

2.hidden = YES

3.alpha = 0-0.01

55、有哪類鎖,鎖的原理?

有兩類鎖:互斥鎖和自旋鎖;還有一種特殊的鎖,叫讀寫鎖,可以用柵欄實(shí)現(xiàn)。

鎖的種類有很多,其中互斥鎖包括遞歸鎖和非遞歸鎖,iOS中的鎖大部分是互斥鎖.

互斥鎖:NSLock,pthread_mutex,@ synchronized,os_unfair_lock

自旋鎖:OSSpinLock,spinlock_t(atomic中使用)

讀寫鎖:pthread_rwlock,可以用dispatch_asyn_banner實(shí)現(xiàn)

遞歸鎖(特殊的互斥鎖): NSRecursiveLock,pthread_mutex

條件鎖(互斥鎖):NSCondition,NSConditionLock(底層是NSCondition,可以通過swift源碼庫(kù)或者匯編查看)

信號(hào)量:dispatch_semaphore

鎖:OSSpinLock、NSLock、NSCondition、semaphore(信號(hào)量)、@synchronized

所以判斷是否發(fā)生死鎖的最好方法就是看有沒有在串行隊(duì)列(當(dāng)然也包括主隊(duì)列)中向這個(gè)隊(duì)列添加任務(wù)。又因?yàn)槲覀冎烂總€(gè)串行隊(duì)列對(duì)應(yīng)一個(gè)線程,所以只要不在某個(gè)線程中調(diào)用會(huì)阻塞這個(gè)線程的方法即可。

事實(shí)上,我們使用同步的方法編程,往往是要求保證任務(wù)之間的執(zhí)行順序是完全確定的。且不說GCD提供了很多強(qiáng)大的功能來滿足這個(gè)需求,向串行隊(duì)列中同步的添加任務(wù)本身就是不合理的,畢竟隊(duì)列已經(jīng)是串行的了,直接異步添加就可以了啊。所以,解決文章開頭那個(gè)死鎖例子的最簡(jiǎn)單的方法就是在合適的位置添加一個(gè)字母a。

56、性能優(yōu)化(比如啟動(dòng)優(yōu)化,編譯優(yōu)化,feed流優(yōu)化,包體積)

啟動(dòng)優(yōu)化有:

(1)啟動(dòng)廣告加載上次緩存數(shù)據(jù),并異步請(qǐng)求下次數(shù)據(jù);

(2)減少動(dòng)態(tài)庫(kù)數(shù)量,合并動(dòng)態(tài)庫(kù)

(3)清理無用類,無用方法,減少分類創(chuàng)建,刪減無用靜態(tài)變量,圖片等,使用APPCode工具掃描未使用的代碼

(4)非必要,不在+load中執(zhí)行代碼

(5)減少啟動(dòng)時(shí)候創(chuàng)建對(duì)象的數(shù)量,盡量異步創(chuàng)建

(6)首屏數(shù)據(jù)緩存,進(jìn)行異步刷新

(7)二進(jìn)制重排,減少缺頁中斷

編譯優(yōu)化有:

(1)非當(dāng)前業(yè)務(wù)使用打包好的庫(kù)

(2)dysm不需要生成,若不需要調(diào)試的話,也可以把本地符號(hào)表的生成去掉

(3)設(shè)置只編譯當(dāng)前架構(gòu)的包

(4)關(guān)閉編譯器優(yōu)化

(5)無用資源文件代碼等

(6)pch文件的適當(dāng)使用,掘金上有人真么說

(7)去掉不必要的文件引用

(8) 頭文件中盡量使用@class來標(biāo)識(shí)類,減少#import,主要是減少二次引用

(9)使用cccache,但是ccache?不支持?Swift?的問題

(10)使用美團(tuán)的hmap

feed流優(yōu)化:

(1)離屏渲染

(2)緩存高度

(3)數(shù)據(jù)預(yù)加載

(4)預(yù)排版,計(jì)算寬高

(5)圖片圓角使用UIGraphics繪制

(6)圖層合并為一個(gè)圖

(7)CALayer替換UIView

(8)避免過多線程,增加線程調(diào)度時(shí)間

包體積優(yōu)化:

(1)無用圖片,代碼刪除

(2)圖片壓縮

(3)圖片放到云端,再不行放到xasset

(4)開啟Bitcode,減少架構(gòu)

(5)重復(fù)方法抽離

57、二進(jìn)制重排

1、添加other c flags,-fsanitize-coverage=func,trace-pc-guard

2、使用createLinkOrder方法,生成

3、Order File設(shè)置${SRCROOT}/link.order

4、Write Link Map File設(shè)置為YES

5、clear一下command+shift+K,再重新編譯command+B后,查看Link Map File

58、iOS常用庫(kù)有哪些?原理是什么?

AFNetworking是封裝的NSURLSession的網(wǎng)絡(luò)請(qǐng)求,由五個(gè)模塊組成:分別由NSURLSession,Security,Reachability,Serialization,UIKit五部分組成。

Masonry使用鏈?zhǔn)阶兂?,返回值是block,block的返回值是對(duì)象。

SDWebImage

含SDWebImageManager、SDWebImageCache、SDWebImageDownloader以及UIView+WebCache擴(kuò)展類

SDWebImageManager?主要是對(duì)創(chuàng)建任務(wù)、判斷是否包含下載任務(wù)、處理圖片在本地還是需要網(wǎng)絡(luò)請(qǐng)求邏輯(在loadImageWithURL中進(jìn)行實(shí)現(xiàn))

SDWebImageCache?主要是對(duì)圖片生成的緩存進(jìn)行處理,包括保存圖片數(shù)據(jù)、清理磁盤及圖片緩存、查找相關(guān)路徑、確定所占的最大內(nèi)存等

SDWebImageDownloader?主要負(fù)責(zé)對(duì)公共信息的處理(請(qǐng)求頭的拼接、block設(shè)置、參數(shù)初始化等)、對(duì)圖片下載進(jìn)行處理,包含下載的最大并發(fā)數(shù)、對(duì)下載任務(wù)的相關(guān)操作以及反饋下載的進(jìn)度及數(shù)據(jù)等

UIView+WebCache是一個(gè)擴(kuò)展類,主要是通過它將SDWebImageManager中開放的相關(guān)方法進(jìn)行調(diào)用然后反饋到UI界面上

MJExtension原理是使用KVC

MJRefresh

59、編譯流程是什么?

預(yù)處理,執(zhí)行宏替換,刪除注釋,條件編譯被解開;詞法分析和語法分析為AST抽象語法樹;靜態(tài)分析,生成IR,會(huì)有類型不匹配的警告;中間代碼生成和代碼優(yōu)化;最后生成匯編碼;鏈接器把編譯產(chǎn)生的.o.a.dyld等生成macho文件。macho就是可執(zhí)行文件

60、iOS有什么崩潰?如何捕獲和修改?

iOS APP系統(tǒng)crash主要分兩類,一類是Objective-C Exception,一類是Unix Signal.Exception

oc exception常見有:數(shù)組越界,字典以nil作為key,方法未實(shí)現(xiàn),未設(shè)置-objc導(dǎo)致分類未加載,遍歷中修改數(shù)據(jù),內(nèi)存不足,kvo監(jiān)聽移除問題

Signal.Exception:調(diào)用abort函數(shù)生成的信號(hào);除0溢出等;訪問自己不允許訪問的內(nèi)存;啟動(dòng)時(shí)間過長(zhǎng);用戶強(qiáng)制退出,沒電;過燙;看門狗干掉。

主要是signal:

信號(hào)類主要通過分析是否是系統(tǒng)crash,還是內(nèi)存泄露、多線程問題等等.

內(nèi)存泄露可以通過instrument定位,也可以在xcode 開啟zombie選擇定位. retain-cycle 可以使用第三方工具檢測(cè).

關(guān)于crash的定位方面,實(shí)際項(xiàng)目也會(huì)接入crash 上報(bào)工具,如騰訊bugly.

這些上報(bào)原理是注冊(cè)對(duì)應(yīng)的處理handleUncaughtException 和信號(hào)監(jiān)聽,比如signal(SIGBUS, handleSignalException);

http://wzxing55.com/2018/11/30/ios-app-crash類型總結(jié)/

61、hash和iseqal?

重寫hash方法和isequal方法;

isequal 先判斷nil和類型;再判斷地址相等,再判斷具體的值;

Hash是用來當(dāng)對(duì)象添加到字典或者set中用的,當(dāng)hash相同時(shí),再去判斷isequal,因此hash盡可能簡(jiǎn)單又更不容易重復(fù);

62、app有哪些狀態(tài)?

Not Running:未運(yùn)行。

Inactive:前臺(tái)非活動(dòng)狀態(tài)。處于前臺(tái),但是不能接受事件處理。

Active:前臺(tái)活動(dòng)狀態(tài)。處于前臺(tái),能接受事件處理。

Background:后臺(tái)狀態(tài)。進(jìn)入后臺(tái),如果又可執(zhí)行代碼,會(huì)執(zhí)行代碼,代碼執(zhí)行完畢,程序進(jìn)行掛起。

Suspended:掛起狀態(tài)。進(jìn)入后臺(tái),不能執(zhí)行代碼,如果內(nèi)存不足,程序會(huì)被殺死。

63、UIWebView & WKWebView 區(qū)別?

1.運(yùn)行速度更快,占用內(nèi)存更少。WKWebView 在獨(dú)立于app進(jìn)程之外的進(jìn)程中執(zhí)行網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求數(shù)據(jù)不經(jīng)過主進(jìn)程。

2.WKWebView 更快(占用內(nèi)存可能只有 UIWebView 的1/3~1/4),沒有緩存,更為細(xì)致地拆分了 UIWebViewDelegate 中的方法。

3.支持了更多的HTML5特性;

4.高達(dá)60fps的滾動(dòng)刷新率以及內(nèi)置手勢(shì);

5.允許JavaScript的Nitro庫(kù)加載并使用(UIWebView中限制);

64、UIView和CALayer?

首先UIView可以響應(yīng)事件,Layer不可以.

UIView是CALayer的delegate

UIView主要處理事件,CALayer負(fù)責(zé)繪制就更好

每個(gè) UIView 內(nèi)部都有一個(gè) CALayer 在背后提供內(nèi)容的繪制和顯示,并且 UIView 的尺寸樣式都由內(nèi)部的 Layer 所提供。兩者都有樹狀層級(jí)結(jié)構(gòu),layer 內(nèi)部有 SubLayers,View 內(nèi)部有 SubViews.但是 Layer 比 View 多了個(gè)AnchorPoint

65、設(shè)計(jì)模式六大原則?設(shè)計(jì)模式有哪些

六大原則

單一職責(zé)(類的功能要單一),開閉原則(可擴(kuò)展不可修改),里式替換(子類代替父類),依賴倒置(依賴的單向性,模塊不要互相依賴,實(shí)現(xiàn)(細(xì)節(jié))依賴接口(抽象)),接口隔離(協(xié)議的功能要單一),迪米特法則(一個(gè)對(duì)象對(duì)其他對(duì)象要有最小的了解)

開閉原則

對(duì)模塊,類,函數(shù)修改是關(guān)閉的,擴(kuò)展是開放的。即軟件實(shí)體盡量在不修改原有代碼的基礎(chǔ)上進(jìn)行擴(kuò)展

依賴倒置

模塊間的依賴通過抽象來發(fā)生,實(shí)現(xiàn)類之間不產(chǎn)生直接依賴關(guān)系,其依賴關(guān)系通過接口或者抽象類生成。接口和抽象類不依賴實(shí)現(xiàn)類,實(shí)現(xiàn)類依賴接口或抽象類。

單一職責(zé)

每個(gè)類應(yīng)該實(shí)現(xiàn)單一職責(zé),否則應(yīng)該把類拆分,避免類的臃腫和復(fù)用性差。

迪米特原則

最少知識(shí)原則,一個(gè)類盡量不要和其他類發(fā)生關(guān)系,對(duì)外界知道越少,耦合性越低,當(dāng)修改時(shí)對(duì)外界的影響也就越小。

里氏替換原則

里氏替換原則通常拿來和繼承對(duì)比,它的定義:使用父類的地方能夠使用子類來替換,子類的所有方法必須在父類中聲明,或子類必須實(shí)現(xiàn)父類中聲明的所有方法。

繼承的優(yōu)缺點(diǎn):

優(yōu)點(diǎn):提高代碼復(fù)用性,提高代碼的可擴(kuò)展性,子類形似父類,但又保留自己的特性;

缺點(diǎn):侵入性,不夠靈活,耦合度高

里氏替換原則規(guī)則為解決繼承關(guān)系的侵入性和高耦合使用方法:

1.子類必須實(shí)現(xiàn)父類的抽象方法,但不得重寫(覆蓋)父類的非抽象(已實(shí)現(xiàn))方法

2.子類中可以增加自己特有的方法

3.當(dāng)子類重載父類的方法時(shí),方法的前置條件(即方法的形參)要比父類方法的輸入?yún)?shù)更寬松

4.當(dāng)子類的方法實(shí)現(xiàn)父類的抽象方法時(shí),方法的后置條件(即方法的返回值)要比父類更嚴(yán)格

接口隔離法則

一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接口上。一個(gè)類不應(yīng)該依賴他不需要的接口,接口不應(yīng)該存在子類用不到但是必須實(shí)現(xiàn)的方法,否則需要進(jìn)行拆分。接口粒度需要盡可能小。

http://www.itdecent.cn/p/1f56168fe5b5

設(shè)計(jì)模式:

創(chuàng)建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。

結(jié)構(gòu)型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責(zé)任鏈模式、命令模式、備忘錄模式、狀態(tài)模式、訪問者模式、中介者模式、解釋器模式。

66、自動(dòng)布局與frame?

autoLayout需要將約束之類的計(jì)算成frame的形態(tài),比較消耗cpu資源,特別是如何視圖比較復(fù)雜頁面渲染的時(shí)候不夠流程,可能要考慮將autoLayout改成用frame直接布局

67、webview的加載流程?

初始化webview -> 請(qǐng)求頁面 -> 下載數(shù)據(jù) -> 解析HTML -> 請(qǐng)求 js/css 資源 -> dom 渲染 -> 解析 JS 執(zhí)行 -> JS 請(qǐng)求數(shù)據(jù) -> 解析渲染 -> 下載渲染圖片

68、udp和tcp的區(qū)別?

udptcp

是否連接無連接面向連接

是否可靠不可靠傳輸,不使用流量控制和擁塞控制可靠傳輸,使用流量控制和擁塞控制

連接對(duì)象個(gè)數(shù)支持一對(duì)一,一對(duì)多,多對(duì)一和多對(duì)多交互通信只能是一對(duì)一通信

傳輸方式面向報(bào)文面向字節(jié)流

首部開銷首部開銷小,僅8字節(jié) 首部最小20字節(jié),最大60字節(jié)

適用場(chǎng)景適用于實(shí)時(shí)應(yīng)用(IP電話、視頻會(huì)議、直播等)適用于要求可靠傳輸?shù)膽?yīng)用,例如文件傳輸

69、iOS 圖像渲染原理?

70、什么是長(zhǎng)連接?心跳跟輪詢的區(qū)別?

長(zhǎng)連接:連接->傳輸數(shù)據(jù)->保持連接 -> 傳輸數(shù)據(jù)-> ....->直到一方關(guān)閉連接,客戶端關(guān)閉連接。

長(zhǎng)連接指建立SOCKET連接后不管是否使用都保持連接,但安全性較差。

短連接:連接->傳輸數(shù)據(jù)->關(guān)閉連接。

比如HTTP是無狀態(tài)的的短鏈接,瀏覽器和服務(wù)器每進(jìn)行一次HTTP操作,就建立一次連接,但任務(wù)結(jié)束就中斷連接。因?yàn)檫B接后接收了數(shù)據(jù)就斷開了,所以每次數(shù)據(jù)接受處理不會(huì)有聯(lián)系。這也是HTTP協(xié)議無狀態(tài)的原因之一。

71、說一下什么是runloop?卡頓監(jiān)聽為什么是那兩個(gè)狀態(tài)?

RunLoop 就是一個(gè)跟線程一一對(duì)應(yīng)的事件處理的循環(huán),用來不斷的循環(huán)處理一些事件。使用 RunLoop 的目的是讓你的線程在有工作的時(shí)候忙于工作,而沒工作的時(shí)候休息。 runloop 的設(shè)計(jì)是為了減少 cpu 無謂的空轉(zhuǎn)。可以是一個(gè)狀態(tài)機(jī)的概念。

使用場(chǎng)景:

1、需要使用 Port 其他線程進(jìn)行通訊;

2、定時(shí)器;

3、performSelector的延時(shí)操作;

4、子線程保活;

另外,只有主線程在開始的時(shí)候開啟了runloop

這跟runloop的執(zhí)行順序有關(guān),BeforeSources之后,主要是響應(yīng)UIEvent,也就是處理Source0。如果這個(gè)狀態(tài)太久,說明這個(gè)app沒辦法響應(yīng)點(diǎn)擊事件了。

AfterWaiting之后,說明當(dāng)前線程剛被喚醒,準(zhǔn)備執(zhí)行被喚醒的事件了。但又卡在這個(gè)狀態(tài),沒有去執(zhí)行。也能說明當(dāng)前App卡頓。

nstimer強(qiáng)引用,displaylink 幀率,可以自己設(shè)置;autorelease監(jiān)聽的兩個(gè)通知;runloop監(jiān)聽卡頓,aftersource和afterwait之間。

72、說一下什么是runtime?

運(yùn)行時(shí),方法替換,分類,關(guān)聯(lián)對(duì)象。fishhook原理,innerhook。

把很多別的語言編譯時(shí)候干的事情放到了運(yùn)行期間

OC這門語言的的動(dòng)態(tài)性是有RunTime來支撐和實(shí)現(xiàn)的,Runtime是一套基于C的API接口,封裝了很多跟動(dòng)態(tài)性相關(guān)的函數(shù)

方法的調(diào)用,方法的新增,轉(zhuǎn)換等都依賴于runtime

73、函數(shù)式編程和鏈?zhǔn)骄幊?/p>

如果想再去調(diào)用別的方法,那么就需要返回一個(gè)對(duì)象;

如果想用()去執(zhí)行,那么需要返回一個(gè)block;

如果想讓返回的block再調(diào)用對(duì)象的方法,那么這個(gè)block就需要返回一個(gè)對(duì)象(即返回值為一個(gè)對(duì)象的block)。

74、埋點(diǎn)方案

①代碼埋點(diǎn)就是在代碼里需要上報(bào)的地方添加上報(bào)的代碼。

優(yōu)點(diǎn)

開發(fā)簡(jiǎn)單。

可以精確的控制上報(bào)的事件和時(shí)機(jī)。

方便地把自定義的事件和詳細(xì)的參數(shù)上報(bào)。

缺點(diǎn)

對(duì)代碼侵入比較大。

埋點(diǎn)工作量大,必須是技術(shù)開發(fā)人員完成。

更新或新增埋點(diǎn)成本較高,如果遇到漏埋或者需要新埋的點(diǎn),需要重新發(fā)版。

②可視化埋點(diǎn)是用可視化的方式,提前把需要采集的控件事件進(jìn)行圈選,并下發(fā)給客戶端,用戶進(jìn)行操作時(shí),埋點(diǎn)SDK會(huì)自動(dòng)根據(jù)下發(fā)的配置進(jìn)行上報(bào),不需要進(jìn)行代碼埋點(diǎn)。

Mixpanel 提供了可視化埋點(diǎn)的方案,并且把代碼進(jìn)行了開源。SensorsData 參考了 Mixpanel,也進(jìn)行了開源。本文介紹的技術(shù)方案方案參考了這兩個(gè)開源框架。

優(yōu)點(diǎn)

解決了代碼埋點(diǎn)的侵入性、工作量和發(fā)版成本問題。

缺點(diǎn)

不是所有的事件都可以圈選埋點(diǎn),比如一些和業(yè)務(wù)邏輯耦合比較緊的事件埋點(diǎn)。

無法在埋點(diǎn)時(shí)增加自定義的字段。

③無埋點(diǎn)

優(yōu)點(diǎn)

在可視化埋點(diǎn)的基礎(chǔ)上,可以分析已經(jīng)上報(bào)的數(shù)據(jù)。也就是如果哪天突然想對(duì)某個(gè)用戶操作進(jìn)行分析,歷史數(shù)據(jù)也可以分析。

缺點(diǎn)

不是所有的事件都可以圈選埋點(diǎn),比如一些和業(yè)務(wù)邏輯耦合比較緊的事件埋點(diǎn)。

無法在埋點(diǎn)時(shí)增加自定義的字段。

此外因?yàn)樯蠄?bào)了所有的用戶的操作,相比可視化埋點(diǎn)網(wǎng)絡(luò)負(fù)擔(dān)稍微增大。

下面列出部分第三方埋點(diǎn)框架:

Mixpanel(開源)

SensorsData(神策)(開源)

Heap

GrowingIO

MTA(騰訊移動(dòng)分析)

友盟

TalkingData

MTJ(百度移動(dòng)統(tǒng)計(jì))

GoogleAnalytics(谷歌統(tǒng)計(jì))

HubbleData(網(wǎng)易內(nèi)部使用)

74、SEL 和 IMP 是什么

SEL : 類成員方法的指針,但不同于C語言中的函數(shù)指針,函數(shù)指針直接保存了方法的地址,但SEL只是方法編號(hào)。

IMP:一個(gè)函數(shù)指針,保存了方法的地址

IMP和SEL關(guān)系

每一個(gè)繼承于NSObject的類都能自動(dòng)獲得runtime的支持。在這樣的一個(gè)類中,有一個(gè)isa指針,指向該類定義的數(shù)據(jù)結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體是由編譯器編譯時(shí)為類(需繼承于NSObject)創(chuàng)建的.在這個(gè)結(jié)構(gòu)體中有包括了指向其父類類定義的指針以及 Dispatch table. Dispatch table是一張SEL和IMP的對(duì)應(yīng)表。

也就是說方法編號(hào)SEL最后還是要通過Dispatch table表尋找到對(duì)應(yīng)的IMP,IMP就是一個(gè)函數(shù)指針,然后執(zhí)行這個(gè)方法。

75、HTTPS加解密流程

用戶在瀏覽器發(fā)起HTTPS請(qǐng)求,默認(rèn)使用服務(wù)端的443端口進(jìn)行連接;

HTTPS需要使用一套CA數(shù)字證書,證書內(nèi)會(huì)附帶一個(gè)公鑰,而與之對(duì)應(yīng)的私鑰保留在服務(wù)端不公開;

服務(wù)端收到請(qǐng)求,返回配置好的包含公鑰的證書給客戶端;

客戶端收到證書,校驗(yàn)合法性,主要包括是否在有效期內(nèi)、證書的域名與請(qǐng)求的域名是否匹配,上一級(jí)證書是否有效(遞歸判斷,直到判斷到系統(tǒng)內(nèi)置或?yàn)g覽器配置好的根證書),如果不通過,則顯示HTTPS警告信息,如果通過則繼續(xù);

客戶端生成一個(gè)用于對(duì)稱加密的隨機(jī)Key,并用證書內(nèi)的公鑰進(jìn)行加密,發(fā)送給服務(wù)端;

服務(wù)端收到隨機(jī)Key的密文,使用與公鑰配對(duì)的私鑰進(jìn)行解密,得到客戶端真正想發(fā)送的隨機(jī)Key;

服務(wù)端使用客戶端發(fā)送過來的隨機(jī)Key對(duì)要傳輸?shù)腍TTP數(shù)據(jù)進(jìn)行對(duì)稱加密,將密文返回客戶端;

客戶端使用隨機(jī)Key對(duì)稱解密密文,得到HTTP數(shù)據(jù)明文;

后續(xù)HTTPS請(qǐng)求使用之前交換好的隨機(jī)Key進(jìn)行對(duì)稱加解密。

76、網(wǎng)絡(luò)七層概述

77、堆棧

棧區(qū)(stack):由編譯器自動(dòng)分配釋放,存放函數(shù)的參數(shù)值,局部變量等值。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

存放的局部變量、先進(jìn)后出、一旦出了作用域就會(huì)被銷毀;函數(shù)跳轉(zhuǎn)地址,現(xiàn)場(chǎng)保護(hù)等;

程序猿不需要管理?xiàng)^(qū)變量的內(nèi)存; 棧區(qū)地址從高到低分配;

堆區(qū)(heap):一般由程序員分配釋放,若程序員不釋放,則可能會(huì)引起內(nèi)存泄漏。注堆和數(shù)據(jù)結(jié)構(gòu)中的堆棧不一樣,其類是與鏈表。

堆區(qū)的內(nèi)存分配使用的是alloc;需要程序猿管理內(nèi)存;ARC的內(nèi)存的管理,是編譯器再編譯的時(shí)候自動(dòng)添加 retain、release、autorelease;

堆區(qū)的地址是從低到高分配)

包括兩個(gè)部分:未初始化過 、初始化過; 也就是說,(全局區(qū)/靜態(tài)區(qū))在內(nèi)存中是放在一起的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域; eg:int a;未初始化的。int a = 10;已初始化的。

78、串行隊(duì)列和并行隊(duì)列的同步、異步順序

https://blog.csdn.net/feisongfeiqin/article/details/50282273

①串行隊(duì)列 異步任務(wù),會(huì)創(chuàng)建子線程,且只創(chuàng)建一個(gè)子線程,異步任務(wù)執(zhí)行是有序的。

②串行隊(duì)列 同步任務(wù),不創(chuàng)建新線程,同步任務(wù)執(zhí)行是有序的。?

③并行隊(duì)列 異步任務(wù),會(huì)創(chuàng)建子線程,且多個(gè)子線程,異步任務(wù)打印結(jié)果無序。?

④并行隊(duì)列 同步任務(wù),不創(chuàng)建新線程,同步任務(wù)執(zhí)行是有序的。?

⑤串行隊(duì)列 先異步再同步,打印1,添加2任務(wù)掛起,打印3,添加同步4阻塞掛起,執(zhí)行2任務(wù),執(zhí)行4任務(wù),執(zhí)行5任務(wù)

⑥串行隊(duì)列 先同步再異步,打印1,添加同步2執(zhí)行2,打印3,添加4掛起,打印5,執(zhí)行4任務(wù)

⑦并行隊(duì)列 先異步再同步,打印1,添加2任務(wù)掛起,打印3,添加同步4執(zhí)行4,執(zhí)行5,2在3之后隨機(jī)

⑧并行隊(duì)列 先同步再異步,打印1,添加同步2執(zhí)行2,打印3,添加任務(wù)4掛起,打印5,打印4

同步、異步?jīng)Q定是否創(chuàng)建子線程,同步任務(wù)不創(chuàng)建子線程,都是在主線程中執(zhí)行,異步任務(wù)創(chuàng)建子線程。?

串行、并行決定創(chuàng)建子線程的個(gè)數(shù),串行創(chuàng)建一個(gè)子線程,并行創(chuàng)建多個(gè)子線程(具體幾個(gè)由系統(tǒng)決定)。?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容