[iOS知識簡記]-題庫走查1

https://www.jianshu.com/p/75e4b9fdcf41
這裏的題庫走查。

算法

6 如何查找兩個子視圖的共同父視圖?

給的解法不是最優,可以不利用數組記錄所有父節點,直接遍歷算長度就可以。
類似找2個單向鏈表的公共節點,算2個鏈表的長度,做差,然後長鏈表偏移後同時遍歷。

8 如何給定一個整數數組和一個目標值,找出數組中和爲目標值的兩個數。

給的解法不是最優,可以先排序,然後再O(n)量級的左右兩邊向內遍歷求和。

內存管理

5 @protocol和category中如何使用@property

在 protocol 中使用 property 只會生成 setter 和 getter 方法聲明,
我們使用屬性的目的,是希望遵守我協議的對象能實現該屬性。
category 使用 @property 也是隻會生成 setter 和 getter 方法的聲明,
如果我們真的需要給 category 增加屬性的實現,需要藉助於運行時的兩個函數:
objc_setAssociatedObject和objc_getAssociatedObject。

6 BAD_ACCESS在什麼情況下出現?

給的答案都不夠本質和底層。

8 iOS內存管理方式

has_sidetable_rc/extra_rc/SideTables等細看

10 ARC 的 retainCount 怎麼存儲的?

存在64張哈希表中,根據哈希算法去查找所在的位置,無需遍歷,十分快捷。
散列表(引用計數表、weak表):
SideTables 表在 非嵌入式的64位系統中,有 64張 SideTable 表
每一張 SideTable 主要是由三部分組成。自旋鎖、引用計數表、弱引用表。
全局的 引用計數 之所以不存在同一張表中,是爲了避免資源競爭,解決效率的問題。
引用計數表 中引入了 分離鎖的概念,將一張表分拆成多個部分,對他們分別加鎖,可以實現併發操作,
提升執行效率:
引用計數表(哈希表)
通過指針的地址,查找到引用計數的地址,大大提升查找效率
通過 DisguisedPtr(objc_object) 函數存儲,同時也通過這個函數查找,這樣就避免了循環遍歷。

消息傳遞的方式

1 KVC的實現原理

KVC,鍵-值編碼,使用字符串直接訪問對象的屬性。
底層實現,當一個對象調用setValue方法時,方法內部會做以下操作:
檢查是否存在相應key的set方法,如果存在,就調用set方法
如果set方法不存在,就會查找與key相同名稱並且帶下劃線的成員屬性,如果有,則直接給成員屬性賦值
如果沒有找到_key,就會查找相同名稱的屬性key,如果有就直接賦值
如果還沒找到,則調用valueForUndefinedKey:和setValue:forUndefinedKey:方法

2 KVO的實現原理

1.當給A類添加KVO的時候,runtime動態的生成了一個子類NSKVONotifying_A,
讓A類的isa指針指向NSKVONotifying_A類,重寫class方法,隱藏對象真實類信息
2.重寫監聽屬性的setter方法,在setter方法內部調用了Foundation 的 
_NSSetObjectValueAndNotify 函數
3._NSSetObjectValueAndNotify函數內部
a) 首先會調用 willChangeValueForKey
b) 然後給屬性賦值
c) 最後調用 didChangeValueForKey
d) 最後調用 observer 的 observeValueForKeyPath 去告訴監聽器屬性值發生了改變 .
4.重寫了dealloc做一些 KVO 內存釋放

6 爲什麼Block用copy關鍵字?

Block在沒有使用外部變量時,內存存在全局區,然而,當Block在使用外部變量的時候,
內存是存在於棧區,當Block copy之後,是存在堆區的。
存在於棧區的特點是對象隨時有可能被銷燬,一旦銷燬在調用的時候,就會造成系統的崩潰。
所以Block要用copy關鍵字。
------ ARC後,還有幾個存放在棧區的???所以也不關鍵了吧???

動畫

1 UIView動畫與核心動畫的區別?

核心動畫只作用在layer.
核心動畫修改的值都是假像.它的真實位置沒有發生變化.
當需要與用戶進行交互時用UIView動畫,不需要與用戶進行交互時兩個都可以.

2 當我們要做一些基於 CALayer 的動畫時,有時需要設置 layer 的錨點來配合動畫,這時候我們需要注意什麼?

需要注意的是設置錨點會引起原來 position 的變化,可能會發生不符合預期的行爲,
所以要做一下轉化,示例代碼如下

Runtime

1 Category 的實現原理?

Category 實際上是 Category_t的結構體,在運行時,新添加的方法,
都被以倒序插入到原有方法列表的最前面,所以不同的Category,添加了同一個方法,
執行的實際上是最後一個。
Category 在剛剛編譯完的時候,和原來的類是分開的,只有在程序運行起來後,
通過 Runtime ,Category 和原來的類纔會合併到一起。

2 isa指針的理解,對象的isa指針指向哪裏?isa指針有哪兩種類型?

isa 等價於 is kind of
實例對象的 isa 指向類對象
類對象的 isa 指向元類對象
元類對象的 isa 指向元類的基類
isa 有兩種類型
純指針,指向內存地址
NON_POINTER_ISA,除了內存地址,還存有一些其他信息

4 runtime 如何實現 weak 屬性?

weak 此特質表明該屬性定義了一種「非擁有關係」(nonowning relationship)。
爲這種屬性設置新值時,設置方法既不持有新值(新指向的對象),也不釋放舊值(原來指向的對象)。
runtime 對註冊的類,會進行內存佈局,從一個粗粒度的概念上來講,這時候會有一個 hash 表,
這是一個全局表,表中是用 weak 指向的對象內存地址作爲 key,
用所有指向該對象的 weak 指針表作爲 value。當此對象的引用計數爲 0 的時候會 dealloc,
假如該對象內存地址是 a,那麼就會以 a 爲 key,在這個 weak 表中搜索,
找到所有以 a 爲鍵的 weak 對象,從而設置爲 nil。
runtime 如何實現 weak 屬性具體流程大致分爲 3 步:
1、初始化時:runtime 會調用 objc_initWeak 函數,初始化一個新的 weak 指針指向對象的地址。
2、添加引用時:objc_initWeak 函數會調用 objc_storeWeak() 函數,
objc_storeWeak() 的作用是更新指針指向(指針可能原來指向着其他對象,
這時候需要將該 weak 指針與舊對象解除綁定,會調用到 weak_unregister_no_lock),
如果指針指向的新對象非空,則創建對應的弱引用表,將 weak 指針與新對象進行綁定,
會調用到 weak_register_no_lock。在這個過程中,爲了防止多線程中競爭衝突,
會有一些鎖的操作。
3、釋放時:調用 clearDeallocating 函數,clearDeallocating 函數首先根據對象地址
獲取所有 weak 指針地址的數組,然後遍歷這個數組把其中的數據設爲 nil,
最後把這個 entry 從 weak 表中刪除,最後清理對象的記錄。

7 runtime如何通過selector找到對應的IMP地址?

每一個類對象中都一個對象方法列表(對象方法緩存)
類方法列表是存放在類對象中isa指針指向的元類對象中(類方法緩存)。
方法列表中每個方法結構體中記錄着方法的名稱,方法實現,以及參數類型,
其實selector本質就是方法名稱,通過這個方法名稱就可以在方法列表中找到對應的方法實現。
當我們發送一個消息給一個NSObject對象時,這條消息會在對象的類對象方法列表裏查找。
當我們發送一個消息給一個類時,這條消息會在類的Meta Class對象的方法列表裏查找。

9 load和initialize的區別

load和initialize方法都不用顯示的調用父類的方法而是自動調用,
即使子類沒有initialize方法也會調用父類的方法,而load方法則不會調用父類。
------ TODO:確認下

------ Runtime分類裏好多答案都過於簡單粗糙。

項目架構

1 MVC、MVP、MVVM模式

MVP(Model、View、Presenter)
View與MVC中的View層有一些差別,MVP中的View層可以是viewController、view等控件;
Presenter層則是作爲Model和View的中介,從Model層獲取數據之後傳給View。
從上圖可以看出,從MVC模式中增加了Presenter層,將UIViewController中複雜的業務邏輯、
網絡請求等剝離出來。
MVVM(Model、Controller/View、ViewModel)
在MVVM中,view和ViewCOntroller聯繫在一起,我們把它們視爲一個組件,
view和ViewController都不能直接引用model,而是引用是視圖模型即ViewModel。 
viewModel是一個用來放置用戶輸入驗證邏輯、視圖顯示邏輯、網絡請求等業務邏輯的地方,
這樣的設計模式,會輕微增加代碼量,但是會減少代碼的複雜性

2 關於RAC你有怎樣運用到解決不同API依賴關係

信號的依賴:使用場景是當信號A執行完纔會執行信號B,和請求的依賴很類似,
例如請求A請求完畢才執行請求B,我們需要注意信號A必須要執行發送完成信號,否則信號B無法執行

3 @weakify和我們宏定義的WeakSelf有什麼區別?

@weakify 可以多參數使用

------ 項目架構分類裏的題目都是解決的一些局部問題或某小類問題,架構過小。

設計模式

3 編程中的六大設計原則?

1.單一職責原則
通俗地講就是一個類只做一件事
CALayer:動畫和視圖的顯示。
UIView:只負責事件傳遞、事件響應。
2.開閉原則
對修改關閉,對擴展開放。 要考慮到後續的擴展性,而不是在原有的基礎上來回修改
3.接口隔離原則
使用多個專門的協議、而不是一個龐大臃腫的協議,
如 UITableviewDelegate + UITableViewDataSource
4.依賴倒置原則
抽象不應該依賴於具體實現、具體實現可以依賴於抽象。 調用接口感覺不到內部是如何操作的
5.里氏替換原則
父類可以被子類無縫替換,且原有的功能不受任何影響 如:KVO
6.迪米特法則
一個對象應當對其他對象儘可能少的瞭解,實現高聚合、低耦合

組件化

3 爲什麼CTMediator方案優於基於Router的方案?

4 基於CTMediator的組件化方案,有哪些核心組成?

iOS關於CTMediator組件化實踐的詳解篇
https://www.jianshu.com/p/b1c6d070c92b

性能優化

5 如何檢測離屏渲染與優化

檢測,通過勾選Xcode的Debug->View Debugging-->Rendering->Run
->Color Offscreen-Rendered Yellow項。
優化,如陰影,在繪製時添加陰影的路徑

6 怎麼檢測圖層混合

持續集成

1 你在項目中使用過什麼持續集成方式?

Fastlane:一套用Ruby寫的自動化工具集,可用於iOS和Android的打包、發佈,節省了大量時間。
Fastlane配置比較簡單,主要編寫集成的lane,然後在命令行操作即可
Jenkins:Jenkins比較受歡迎,插件衆多,但對新手來說配置可能稍微麻煩點。

Foundation

5 id 和 instanceType 有什麼區別?

相同點
instancetype 和 id 都是萬能指針,指向對象。
不同點:
1.id 在編譯的時候不能判斷對象的真實類型,
instancetype 在編譯的時候可以判斷對象的真實類型。
2.id 可以用來定義變量,可以作爲返回值類型,可以作爲形參類型;
instancetype 只能作爲返回值類型。

6 self和super的區別

self調用自己方法,super調用父類方法
self是類,super是預編譯指令
[self class] 和 [super class] 輸出是一樣的
self和super底層實現原理
1.當使用 self 調用方法時,會從當前類的方法列表中開始找,如果沒有,就從父類中再找;
而當使用 super 時,則從父類的方法列表中開始找,然後調用父類的這個方法
2.當使用 self 調用時,會使用 objc_msgSend 函數:
 id objc_msgSend(id theReceiver, SEL theSelector, ...)
第一個參數是消息接收者,第二個參數是調用的具體類方法的 selector,
後面是 selector 方法的可變參數。以 [self setName:] 爲例,
編譯器會替換成調用 objc_msgSend 的函數調用,其中 theReceiver 是 self,
theSelector 是 @selector(setName:),這個 selector 是從當前 self 的 
class 的方法列表開始找的 setName,當找到後把對應的 selector 傳遞過去。
3.當使用 super 調用時,會使用 objc_msgSendSuper 函數:
  id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
第一個參數是個objc_super的結構體,第二個參數還是類似上面的類方法的selector
struct objc_super {
    id receiver;
    Class superClass;
};
------ TODO:反彙編看下

7 @synthesize和@dynamic分別有什麼作用?

@property有兩個對應的詞,一個是 @synthesize,一個是 @dynamic。
如果 @synthesize和 @dynamic都沒寫,那麼默認的就是@syntheszie var = _var;
@synthesize 的語義是如果你沒有手動實現 setter 方法和 getter 方法,
那麼編譯器會自動爲你加上這兩個方法。
@dynamic 告訴編譯器:屬性的 setter 與 getter 方法由用戶自己實現,不自動生成。
(當然對於 readonly 的屬性只需提供 getter 即可)。
假如一個屬性被聲明爲 @dynamic var,然後你沒有提供 @setter方法和 @getter 方法,
編譯的時候沒問題,但是當程序運行到 instance.var = someVar,
由於缺 setter 方法會導致程序崩潰;或者當運行到 someVar = var 時,
由於缺 getter 方法同樣會導致崩潰。編譯時沒問題,運行時才執行相應的方法,
這就是所謂的動態綁定。

底層xxx

1 一個 NSObject 對象佔用多少內存空間?

受限於內存分配的機制,一個 NSObject對象都會分配 16byte 的內存空間。
但是實際上在 64位 下,只使用了 8byte;
在32位下,只使用了 4byte
一個 NSObject 實例對象成員變量所佔的大小,實際上是 8 字節
#import <Objc/Runtime>
Class_getInstanceSize([NSObject Class])
本質是
size_t class_getInstanceSize(Class cls)
{
    if (!cls) return 0;
    return cls->alignedInstanceSize();
}
獲取 Obj-C 指針所指向的內存的大小,實際上是16 字節
#import <malloc/malloc.h>
malloc_size((__bridge const void *)obj); 
對象在分配內存空間時,會進行內存對齊,所以在 iOS 中,分配內存空間都是 16字節 的倍數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章