[iOS]底層原理二 : (Runtime滥玷、Runloop)

底層原理一: (OC 本質(zhì)、KVC巍棱、KVO惑畴、Category、Block)
底層原理二: (Runtime航徙、Runloop)
底層原理三 : (多線程如贷、內(nèi)存管理)
底層原理四 : (性能優(yōu)化、架構(gòu))
底層原理五 : (面試題目整理)

十二.Runtime

12.1 runtime介紹

Objective-C是一門動態(tài)性比較強(qiáng)的編程語言到踏,跟C杠袱、C++等語言有著很大的不同
Objective-C的動態(tài)性是由Runtime API來支撐的
Runtime API提供的接口基本都是C語言的,源碼由C\C++\匯編語言編寫

12.2 isa 詳解

在arm64架構(gòu)之前窝稿,isa就是一個(gè)普通的指針霞掺,存儲著Class、Meta-Class對象的內(nèi)存地址
從arm64架構(gòu)開始讹躯,對isa進(jìn)行了優(yōu)化菩彬,變成了一個(gè)共用體(union)結(jié)構(gòu),還使用位域來存儲更多的信息
21.png

12.3 isa詳解 – 位域

22.png

12.4 &(按位與符號介紹)

& 都是1才是1, 一個(gè)1,就是0
0000&0010  可以取出某一個(gè)特定位數(shù)值

掩碼: 用來按位與(&)運(yùn)算的  
1<<0  左移0位 則為0b 0000 0001
1<<1  左移1位 則為0b 0000 0010
1<<2  左移2位 則為0b 0000 0400
1左移幾位

12.5 |(按位或)

| 有1才是1, 一個(gè)1,就是1,2個(gè)0就是0
0000 | 0010 結(jié)果就是 0010

12.6 ~(按位取反)

~  0000 1010 取反位1111 0101

12.7 位域

struct{
    char tall : 1; //表示只占一位 
    char rich : 1;
    char handsome: 1
} test   // 0b0000 0111

12.8 共用體

unioc{
  char bits;
  
  struct{
    char tall : 1; 
    char rich : 1;
    char handsome: 1
   } test    

}

12.9 Class的結(jié)構(gòu)

23.png

12.10 class_rw_t

24.png

12.11 class_ro_t

25.png

12.12 method_t

26.png

12.13 方法緩存

Class內(nèi)部結(jié)構(gòu)中有個(gè)方法緩存(cache_t)潮梯,用散列表(哈希表)來緩存曾經(jīng)調(diào)用過的方法骗灶,可以提高方法的查找速度

27.png
緩存查找
objc-cache.mm
bucket_t * cache_t::find(cache_key_t k, id receiver)

12.14 runtime objc_msgSend() 消息機(jī)制

objc_msgSend(對象,sel_registerName(方法名字字符串))
//  消息接收者(receiver)
//  消息名稱
    
//  OC的方法調(diào)用: 消息機(jī)制,給方法調(diào)用者發(fā)送消息
    
內(nèi)部執(zhí)行分3大階段
1. 消息發(fā)送
2. 動態(tài)方法解析
3. 消息轉(zhuǎn)發(fā)

12.15 消息發(fā)送 過程

1.通過方法名字去 類對象 方法緩存中查找,如果有則返回方法地址
2.如果沒有緩存,則會遍歷 方法列表查找
3.查到了方法返回,并添加到 緩存列表
4.如果沒找到則會去父類緩存中查找,在去父類方法列表中查找,一層一層父類往上找

28.png

12.16 動態(tài)方法解析

1.如果 消息發(fā)送 未找到方法,則會進(jìn)行動態(tài)方法解析
2.如果是 對象方法調(diào)用會 調(diào)用_class_resoveInstanceMethod()
如果是 類方法調(diào)用 調(diào)用 _class_resoveClassMethod()
3.+(BOOL)ResoveInstanceMethod:(SEL) sel{
  // 獲取其他方法
  Method method = class_getInstanceMethod(self,@selector(test));
     
  //動態(tài)添加方法
  class_addMethod(self,
                  @selecetor(test),
                  method_getImplementation(method),
                  method_getTypeEndcoing(method));
                  
   return YES;
  
}
類方法同理

29.png

動態(tài)添加方法

30.png

12.17 消息轉(zhuǎn)發(fā)

// 消息轉(zhuǎn)發(fā)-
-(id)forwardTargetForSelector:(SEL) aSelector{
    //  判斷方法名字
    if(aSelector == @selector(test)){
        //轉(zhuǎn)發(fā)給哪個(gè)對象解決
        return [NSPerson alloc]init];
    }
}
    
// 消息轉(zhuǎn)發(fā)- 方法簽名,返回值類型,參數(shù)類型

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if(aSelector == @selector(testMethod))
    {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return nil;
}
 
 
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
    if (anInvocation.selector == @selector(testMethod))
    {
        TestModelHelper1 *h1 = [[TestModelHelper1 alloc] init];
        TestModelHelper2 *h2 = [[TestModelHelper2 alloc] init];
        [anInvocation invokeWithTarget:h1];
        [anInvocation invokeWithTarget:h2];
    }
}

31.png

12.18 [self class] & [super class]

[super message] 消息接受者還是子類,方法尋找是從父類查找的
super調(diào)用,底層會轉(zhuǎn)換為objc_msgSendSuper2函數(shù)的調(diào)用秉馏,接收2個(gè)參數(shù)
struct objc_super2
SEL
32.png
receiver是消息接收者
current_class是receiver的Class對象

12.19 Runtime的應(yīng)用01 – 查看私有成員變量

33.png

12.20 Runtime的應(yīng)用02 – 字典轉(zhuǎn)模型

利用Runtime遍歷所有的屬性或者成員變量
利用KVC設(shè)值

12.21 runtime 方法交換

class_replaceMethod
method_exchangeImplementations

34.png
35.png
36.png

12.22.常用 api

12.22.1Runtime API01 – 類

動態(tài)創(chuàng)建一個(gè)類(參數(shù):父類耙旦,類名,額外的內(nèi)存空間)
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)

注冊一個(gè)類(要在類注冊之前添加成員變量)
void objc_registerClassPair(Class cls) 

銷毀一個(gè)類
void objc_disposeClassPair(Class cls)

獲取isa指向的Class
Class object_getClass(id obj)

設(shè)置isa指向的Class
Class object_setClass(id obj, Class cls)

判斷一個(gè)OC對象是否為Class
BOOL object_isClass(id obj)

判斷一個(gè)Class是否為元類
BOOL class_isMetaClass(Class cls)

獲取父類
Class class_getSuperclass(Class cls)

12.22.2Runtime API02 – 成員變量

獲取一個(gè)實(shí)例變量信息
Ivar class_getInstanceVariable(Class cls, const char *name)

拷貝實(shí)例變量列表(最后需要調(diào)用free釋放)
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)

設(shè)置和獲取成員變量的值
void object_setIvar(id obj, Ivar ivar, id value)
id object_getIvar(id obj, Ivar ivar)

動態(tài)添加成員變量(已經(jīng)注冊的類是不能動態(tài)添加成員變量的)
BOOL class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types)

獲取成員變量的相關(guān)信息
const char *ivar_getName(Ivar v)
const char *ivar_getTypeEncoding(Ivar v)

12.22.3Runtime API03 – 屬性

獲取一個(gè)屬性
objc_property_t class_getProperty(Class cls, const char *name)

拷貝屬性列表(最后需要調(diào)用free釋放)
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)

動態(tài)添加屬性
BOOL class_addProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
                  unsigned int attributeCount)

動態(tài)替換屬性
void class_replaceProperty(Class cls, const char *name, const objc_property_attribute_t *attributes,
                      unsigned int attributeCount)

獲取屬性的一些信息
const char *property_getName(objc_property_t property)
const char *property_getAttributes(objc_property_t property)

12.22.4Runtime API04 – 方法

獲得一個(gè)實(shí)例方法萝究、類方法
Method class_getInstanceMethod(Class cls, SEL name)
Method class_getClassMethod(Class cls, SEL name)

方法實(shí)現(xiàn)相關(guān)操作
IMP class_getMethodImplementation(Class cls, SEL name) 
IMP method_setImplementation(Method m, IMP imp)
void method_exchangeImplementations(Method m1, Method m2) 

拷貝方法列表(最后需要調(diào)用free釋放)
Method *class_copyMethodList(Class cls, unsigned int *outCount)

動態(tài)添加方法
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

動態(tài)替換方法
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

獲取方法的相關(guān)信息(帶有copy的需要調(diào)用free去釋放)
SEL method_getName(Method m)
IMP method_getImplementation(Method m)
const char *method_getTypeEncoding(Method m)
unsigned int method_getNumberOfArguments(Method m)
char *method_copyReturnType(Method m)
char *method_copyArgumentType(Method m, unsigned int index)

選擇器相關(guān)
const char *sel_getName(SEL sel)
SEL sel_registerName(const char *str)

用block作為方法實(shí)現(xiàn)
IMP imp_implementationWithBlock(id block)
id imp_getBlock(IMP anImp)
BOOL imp_removeBlock(IMP anImp)

十三.runloop

13.1 runloop 簡介

運(yùn)行循環(huán)-在程序運(yùn)行中循環(huán)做一些事情

37.png
應(yīng)用范疇
定時(shí)器(Timer)免都、PerformSelector
GCD Async Main Queue
事件響應(yīng)、手勢識別帆竹、界面刷新
網(wǎng)絡(luò)請求
AutoreleasePool

13.2 runloop 基本作用

RunLoop的基本作用
保持程序的持續(xù)運(yùn)行
處理App中的各種事件(比如觸摸事件绕娘、定時(shí)器事件等)
節(jié)省CPU資源,提高程序性能:該做事時(shí)做事栽连,該休息時(shí)休息
......

13.3 Runloop 對象

iOS中有2套API來訪問和使用RunLoop
Foundation:NSRunLoop

Core Foundation:CFRunLoopRef

NSRunLoop和CFRunLoopRef都代表著RunLoop對象
NSRunLoop是基于CFRunLoopRef的一層OC包裝
CFRunLoopRef是開源的
https://opensource.apple.com/tarballs/CF/

38.png

13.4 runloop 和線程關(guān)系

每條線程都有唯一的一個(gè)與之對應(yīng)的RunLoop對象

RunLoop保存在一個(gè)全局的Dictionary里险领,線程作為key侨舆,RunLoop作為value

線程剛創(chuàng)建時(shí)并沒有RunLoop對象,RunLoop會在第一次獲取它時(shí)創(chuàng)建

RunLoop會在線程結(jié)束時(shí)銷毀

主線程的RunLoop已經(jīng)自動獲染钅啊(創(chuàng)建)挨下,子線程默認(rèn)沒有開啟RunLoop

13.5 獲取RunLoop對象

Foundation
[NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對象
[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對象

Core Foundation
CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對象
CFRunLoopGetMain(); // 獲得主線程的RunLoop對象

13.6 runloop 相關(guān)類

39.png

13.7 CFRunloopModeRef 模式

CFRunLoopModeRef代表RunLoop的運(yùn)行模式

一個(gè)RunLoop包含若干個(gè)Mode,每個(gè)Mode又包含若干個(gè)Source0/Source1/Timer/Observer

RunLoop啟動時(shí)只能選擇其中一個(gè)Mode脐湾,作為currentMode

如果需要切換Mode臭笆,只能退出當(dāng)前Loop,再重新選擇一個(gè)Mode進(jìn)入
- 不同組的Source0/Source1/Timer/Observer能分隔開來秤掌,互不影響

如果Mode里沒有任何Source0/Source1/Timer/Observer耗啦,RunLoop會立馬退出
常見的2種Mode
kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默認(rèn)Mode,通常主線程是在這個(gè)Mode下運(yùn)行

UITrackingRunLoopMode:界面跟蹤 Mode机杜,用于 ScrollView 追蹤觸摸滑動帜讲,保證界面滑動時(shí)不受其他 Mode 影響

40.png

添加Observer監(jiān)聽RunLoop的所有狀態(tài)

41.png

13.8 運(yùn)行邏輯

42.png
43.png
44.png

13.9 RunLoop在實(shí)際開中的應(yīng)用

控制線程生命周期(線程保活)

解決NSTimer在滑動時(shí)停止工作的問題

監(jiān)控應(yīng)用卡頓

性能優(yōu)化

13.10 線程苯忿郑活(常駐線程)

runloop 如果沒有任何 source/source0 timer/observer 就會退出
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末似将,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蚀苛,更是在濱河造成了極大的恐慌在验,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堵未,死亡現(xiàn)場離奇詭異腋舌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)渗蟹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門块饺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雌芽,你說我怎么就攤上這事授艰。” “怎么了世落?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵淮腾,是天一觀的道長。 經(jīng)常有香客問我屉佳,道長谷朝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任武花,我火速辦了婚禮圆凰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘髓堪。我一直安慰自己送朱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布干旁。 她就那樣靜靜地躺著驶沼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪争群。 梳的紋絲不亂的頭發(fā)上回怜,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音换薄,去河邊找鬼玉雾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛轻要,可吹牛的內(nèi)容都是我干的复旬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼冲泥,長吁一口氣:“原來是場噩夢啊……” “哼驹碍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起凡恍,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤志秃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后嚼酝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浮还,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年闽巩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钧舌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涎跨,死狀恐怖延刘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情六敬,我是刑警寧澤碘赖,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站外构,受9級特大地震影響普泡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜审编,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一撼班、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垒酬,春花似錦砰嘁、人聲如沸件炉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斟冕。三九已至,卻和暖如春缅阳,著一層夾襖步出監(jiān)牢的瞬間磕蛇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工十办, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秀撇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓向族,卻偏偏與公主長得像呵燕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子件相,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

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

  • runtime 和 runloop 作為一個(gè)程序員進(jìn)階是必須的虏等,也是非常重要的, 在面試過程中是經(jīng)常會被問到的适肠, ...
    SOI閱讀 21,802評論 3 63
  • runtime 和 runloop 作為一個(gè)程序員進(jìn)階是必須的霍衫,也是非常重要的, 在面試過程中是經(jīng)常會被問到的侯养, ...
    made_China閱讀 1,210評論 0 7
  • 一. OC對象本質(zhì) 1.1 OC對象數(shù)據(jù)結(jié)構(gòu) 我們平時(shí)編寫的Objective-C代碼敦跌,底層實(shí)現(xiàn)其實(shí)都是C\C++...
    Leon_520閱讀 1,926評論 1 7
  • 幸福公社幾位“天使”來鐵嶺“整”幸福小鎮(zhèn),第一天就領(lǐng)略了東北酒文化的深厚功力逛揩,被咱東北的高粱小燒小小“整”了一把柠傍,...
    元初閱讀 411評論 0 0
  • ? 注:筆者的文章是根據(jù)自己當(dāng)前項(xiàng)目做的筆記,具體應(yīng)用請參照自己實(shí)際項(xiàng)目情況 1辩稽、創(chuàng)建應(yīng)用 2惧笛、熱加載,src/i...
    Issho閱讀 1,164評論 0 0