最新整理:iOS面試題-面試常問問題(三)

前言:

最近把 iOS 面試中可能會(huì)遇到的問題整理了一番, 題目大部分是網(wǎng)上收錄的, 方便自己鞏固復(fù)習(xí), 也分享給大家酱床; 希望對(duì)大家有所幫助!

  • 對(duì)于答案拍摇,不一定都合適碗淌,歡迎大家積極討論;整理不易蛤吓,如果您覺得還不錯(cuò)宵喂,麻煩在文末 “點(diǎn)個(gè)贊” ,或者留下您的評(píng)論“Mark” 一下会傲,謝謝您的支持


iOS面試題-面試常問問題(三)

1. 一個(gè)OC對(duì)象占用多少內(nèi)存

  • 系統(tǒng)分配了16個(gè)字節(jié)給NSObject對(duì)象(通過malloc_size函數(shù)獲得)
  • 但NSObject對(duì)象內(nèi)部只使用了8個(gè)字節(jié)的空間(64bit環(huán)境下锅棕,可以通過class_getInstanceSize函數(shù)獲得)

2. 對(duì)象的isa指針指向哪里?

  • instance對(duì)象的isa指向class對(duì)象
  • class對(duì)象的isa指向meta-class對(duì)象
  • meta-class對(duì)象的isa指向基類的meta-class對(duì)象

3.OC的類信息存放在哪里淌山?

  • 對(duì)象方法裸燎、屬性、成員變量泼疑、協(xié)議信息德绿,存放在class對(duì)象中
  • 類方法,存放在meta-class對(duì)象中
  • 成員變量的具體值,存放在instance對(duì)象

4.iOS用什么方式實(shí)現(xiàn)對(duì)一個(gè)對(duì)象的KVO脆炎?(KVO的本質(zhì)是什么梅猿?)

  • 利用RuntimeAPI動(dòng)態(tài)生成一個(gè)子類,并且讓instance對(duì)象的isa指向這個(gè)全新的子類
  • 當(dāng)修改instance對(duì)象的屬性時(shí)秒裕,會(huì)調(diào)用Foundation的_NSSetXXXValueAndNotify函數(shù)
    willChangeValueForKey:
    父類原來的setter
    didChangeValueForKey:
  • 內(nèi)部會(huì)觸發(fā)監(jiān)聽器(Oberser)的監(jiān)聽方法(observeValueForKeyPath:ofObject:change:context:

精選全網(wǎng) · iOS面試題答案PDF文集

image
  • 獲取加小編的iOS技術(shù)交流圈:130 595 548袱蚓,直接獲取

5.如何手動(dòng)觸發(fā)KVO?

手動(dòng)調(diào)用willChangeValueForKey:和didChangeValueForKey:

- (void)viewDidLoad {
[super viewDidLoad];

    Person *person = [[Person alloc]init];;
    [p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    [p willChangeValueForKey:@"name"];
    [p didChangeValueForKey:@"name"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"被觀測對(duì)象:%@, 被觀測的屬性:%@, 值的改變: %@\n, 攜帶信息:%@", object, keyPath, change, context);
}

6.直接修改成員變量會(huì)觸發(fā)KVO么几蜻?

  • 不會(huì)觸發(fā)KVO

7.通過KVC修改屬性會(huì)觸發(fā)KVO么喇潘?

  • 會(huì)觸發(fā)KVO
  • KVC在賦值時(shí)候,內(nèi)部會(huì)觸發(fā)監(jiān)聽器(Oberser)的監(jiān)聽方法(observeValueForKeyPath:ofObject:change:context:) 發(fā)送通知

8.KVC的賦值和取值過程是怎樣的?原理是什么梭稚?

  • KVC的全稱是Key-Value Coding颖低,俗稱“鍵值編碼”,可以通過一個(gè)key來訪問某個(gè)屬性
  • 調(diào)用 setValue:forKey:
    setKey,_setKey ->找到了則進(jìn)行賦值,未找到調(diào)用 accessInstanceVarlableDirctly 是否允許修改value值,返回YES, 調(diào)用_key, _isKey, key, isKey 進(jìn)行賦值

9.Category的使用場合是什么弧烤?

  • 在不修改原有類代碼的情況下,為類添對(duì)象方法或者類方法
  • 或者為類關(guān)聯(lián)新的屬性
  • 分解龐大的類文件

使用場合:

  • 添加實(shí)例方法
  • 添加類方法
  • 添加協(xié)議
  • 添加屬性
  • 關(guān)聯(lián)成員變量

10.Category的實(shí)現(xiàn)原理

  • Category編譯之后的底層結(jié)構(gòu)是struct category_t忱屑,里面存儲(chǔ)著分類的對(duì)象方法、類方法暇昂、屬性莺戒、協(xié)議信息
  • 在程序運(yùn)行的時(shí)候,runtime會(huì)將Category的數(shù)據(jù)急波,合并到類信息中(類對(duì)象从铲、元類對(duì)象中)

11.Category和Class Extension的區(qū)別是什么?

  • Class Extension在編譯的時(shí)候澄暮,它的數(shù)據(jù)就已經(jīng)包含在類信息中
  • Category是在運(yùn)行時(shí)名段,才會(huì)將數(shù)據(jù)合并到類信息中

12.Category中有l(wèi)oad方法嗎?load方法是什么時(shí)候調(diào)用的泣懊?load 方法能繼承嗎伸辟?

  • 有l(wèi)oad方法
  • load方法在runtime加載類、分類的時(shí)候調(diào)用
  • load方法可以繼承馍刮,但是一般情況下不會(huì)主動(dòng)去調(diào)用load方法自娩,都是讓系統(tǒng)自動(dòng)調(diào)用

13. initialize方法如何調(diào)用,以及調(diào)用時(shí)機(jī)

  • 當(dāng)類第一次收到消息的時(shí)候會(huì)調(diào)用類的initialize方法
  • 是通過 runtime 的消息機(jī)制 objc_msgSend(obj,@selector()) 進(jìn)行調(diào)用的
  • 優(yōu)先調(diào)用分類的 initialize, 如果沒有分類會(huì)調(diào)用 子類的,如果子類未實(shí)現(xiàn)則調(diào)用 父類的

14. load、initialize方法的區(qū)別什么渠退?它們?cè)赾ategory中的調(diào)用的順序忙迁?以及出現(xiàn)繼承時(shí)他們之間的調(diào)用過程?

  • load 是類加載到內(nèi)存時(shí)候調(diào)用, 優(yōu)先父類->子類->分類
  • initialize 是類第一次收到消息時(shí)候調(diào)用,優(yōu)先分類->子類->父類
  • 同級(jí)別和編譯順序有關(guān)系
  • load 方法是在 main 函數(shù)之前調(diào)用的

15. Category能否添加成員變量碎乃?如果可以姊扔,如何給Category添加成員變量?

  • 不能直接給Category添加成員變量梅誓,但是可以間接實(shí)現(xiàn)Category有成員變量的效果
  • Category是發(fā)生在運(yùn)行時(shí),編譯完畢,類的內(nèi)存布局已經(jīng)確定,無法添加成員變量(Category的底層數(shù)據(jù)結(jié)構(gòu)也沒有成員變量的結(jié)構(gòu))
  • 可以通過 runtime 動(dòng)態(tài)的關(guān)聯(lián)屬性

16. block的原理是怎樣的恰梢?本質(zhì)是什么佛南?

  • block 本質(zhì)其實(shí)是OC對(duì)象
  • block 內(nèi)部封裝了函數(shù)調(diào)用以及調(diào)用環(huán)境

17. __block的作用是什么?有什么使用注意點(diǎn)嵌言?

  • 如果需要在 block 內(nèi)部修改外部的 局部變量的值,就需要使用__block 修飾(全局變量和靜態(tài)變量不需要加__block 可以修改)
  • __block 修飾以后,局部變量的數(shù)據(jù)結(jié)構(gòu)就會(huì)發(fā)生改變,底層會(huì)變成一個(gè)結(jié)構(gòu)體的對(duì)象,結(jié)構(gòu)內(nèi)部會(huì)聲明 一個(gè) __block修飾變量的成員, 并且將 __block修飾變量的地址保存到堆內(nèi)存中. 后面如果修改 這個(gè)變量的值,可以通過 isa 指針找到這個(gè)結(jié)構(gòu)體,進(jìn)來修改 這個(gè)變量的值;
  • 可以在 block 內(nèi)部修改 變量的值

18. block的屬性修飾詞為什么是copy嗅回?使用block有哪些使用注意?

  • block 一旦沒有進(jìn)行copy操作摧茴,就不會(huì)在堆上
  • 使用注意:循環(huán)引用問題 (外部使用__weak 解決)

19. block在修改NSMutableArray绵载,需不需要添加__block?

  • 如果是操作 NSMutableArray 對(duì)象不需要,因?yàn)?block 內(nèi)部拷貝了 NSMutableArray對(duì)象的內(nèi)存地址,實(shí)際是通過內(nèi)存地址操作的
  • 如果 NSMutableArray 對(duì)象要重新賦值,就需要加__block

20. Block 內(nèi)部為什么不能修改局部變量,需要加__block

  • 通過查看Block 源碼,可以發(fā)現(xiàn), block 內(nèi)部如果單純使用 外部變量, 會(huì)在 block 內(nèi)部創(chuàng)建同樣的一個(gè)變量,并且將 外部變量的值引用過來..(只是將外部變量值拷貝到 block 內(nèi)部), 內(nèi)部這個(gè)變量和外部 實(shí)際已經(jīng)沒關(guān)系了
  • 從另一方面分析,block 本質(zhì)也是一個(gè) 函數(shù)指針, 外部的變量也是一個(gè)局部變量,很有可能 block 在使用這個(gè)變量時(shí)候,外部變量已經(jīng)釋放了,會(huì)造成錯(cuò)誤
  • 加了__block 以后, 會(huì)將外部變量的內(nèi)存拷貝到堆中, 內(nèi)存由 block 去管理.

精選全網(wǎng) · iOS面試題答案PDF文集

image
  • 獲取加小編的iOS技術(shù)交流圈:130 595 548苛白,直接獲取

21. 講一下 OC 的消息機(jī)制

  • OC中的方法調(diào)用其實(shí)都是轉(zhuǎn)成了objc_msgSend函數(shù)的調(diào)用娃豹,給receiver(方法調(diào)用者)發(fā)送了一條消息(selector方法名)
  • objc_msgSend底層有3大階段
    • 消息發(fā)送(當(dāng)前類、父類中查找)购裙、
    • 動(dòng)態(tài)方法解析懂版、
    • 消息轉(zhuǎn)發(fā)

22. 消息發(fā)送流程

  • 當(dāng)我們的一個(gè) receiver(實(shí)例對(duì)象)收到消息的時(shí)候, 會(huì)通過 isa 指針找到 他的類對(duì)象, 然后在類對(duì)象方法列表中查找 對(duì)應(yīng)的方法實(shí)現(xiàn),如果 未找到,則會(huì)通過 superClass 指針找到其父類的類對(duì)象, 找到則返回,未找打則會(huì)一級(jí)一級(jí)往上查到,最終到NSObject 對(duì)象, 如果還是未找到就會(huì)進(jìn)行動(dòng)態(tài)方法解析
  • 類方法調(diào)用同上,只不過 isa 指針找到元類對(duì)象;

23. 動(dòng)態(tài)方法解析機(jī)制

當(dāng)我們發(fā)送消息未找到方法實(shí)現(xiàn),就會(huì)進(jìn)入第二步,動(dòng)態(tài)方法解析: 代碼實(shí)現(xiàn)如下

//  動(dòng)態(tài)方法綁定- 實(shí)例法法調(diào)用
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(run)) {
        Method method = class_getInstanceMethod(self, @selector(test));
        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
// 類方法調(diào)用
+(BOOL) resolveClassMethod:(SEL)sel....

24.消息轉(zhuǎn)發(fā)機(jī)制流程

未找到動(dòng)態(tài)方法綁定,就會(huì)進(jìn)行消息轉(zhuǎn)發(fā)階段

// 快速消息轉(zhuǎn)發(fā)- 指定消息處理對(duì)象
- (id)forwardingTargetForSelector:(SEL)aSelector{
    if (aSelector == @selector(run)) {
        return [Student new];
    }
    return  [super forwardingTargetForSelector:aSelector];
} 

// 標(biāo)準(zhǔn)消息轉(zhuǎn)發(fā)-消息簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    if(aSelector == @selector(run))
    {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
   //內(nèi)部邏輯自己處理 
}

25. 什么是Runtime?平時(shí)項(xiàng)目中有用過么躏率?

  • Objective-C runtime是一個(gè)運(yùn)行時(shí)庫躯畴,它為Objective-C語言的動(dòng)態(tài)特性提供支持,我們所寫的OC代碼在運(yùn)行時(shí)都轉(zhuǎn)成了runtime相關(guān)的代碼薇芝,類轉(zhuǎn)換成C語言對(duì)應(yīng)的結(jié)構(gòu)體蓬抄,方法轉(zhuǎn)化為C語言對(duì)應(yīng)的函數(shù),發(fā)消息轉(zhuǎn)成了C語言對(duì)應(yīng)的函數(shù)調(diào)用恩掷。通過了解runtime以及源碼,可以更加深入的了解OC其特性和原理
  • OC是一門動(dòng)態(tài)性比較強(qiáng)的編程語言倡鲸,允許很多操作推遲到程序運(yùn)行時(shí)再進(jìn)行
  • OC的動(dòng)態(tài)性就是由Runtime來支撐和實(shí)現(xiàn)的供嚎,Runtime是一套C語言的API黄娘,封裝了很多動(dòng)態(tài)性相關(guān)的函數(shù)
  • 平時(shí)編寫的OC代碼,底層都是轉(zhuǎn)換成了Runtime API進(jìn)行調(diào)用

26. runtime具體應(yīng)用

  • 利用關(guān)聯(lián)對(duì)象(AssociatedObject)給分類添加屬性
  • 遍歷類的所有成員變量(修改textfield的占位文字顏色克滴、字典轉(zhuǎn)模型逼争、自動(dòng)歸檔解檔)
  • 交換方法實(shí)現(xiàn)(交換系統(tǒng)的方法)
  • 利用消息轉(zhuǎn)發(fā)機(jī)制解決方法找不到的異常問題

27. unrecognized selector sent to instance 錯(cuò)誤

該錯(cuò)誤是基于OC的消息機(jī)制:

  1. 在方法列表中未找到方法實(shí)現(xiàn)
  2. 嘗試動(dòng)態(tài)方法解析,也未綁定犯法
  3. 進(jìn)行消息轉(zhuǎn)發(fā),也未處理
  4. 最后進(jìn)行報(bào)錯(cuò)

28. 如果向一個(gè)nil對(duì)象發(fā)消息不會(huì)crash的話,那么message sent to deallocated instance的錯(cuò)誤是怎么回事?

  • 這是因?yàn)檫@個(gè)對(duì)象已經(jīng)被釋放了(引用計(jì)數(shù)為0了)劝赔,那么這個(gè)時(shí)候再去調(diào)用方法肯定是會(huì)Crash的誓焦,因?yàn)檫@個(gè)時(shí)候這個(gè)對(duì)象就是一個(gè)野指針(指向僵尸對(duì)象(對(duì)象的引用計(jì)數(shù)為0,指針指向的內(nèi)存已經(jīng)不可用)的指針)了着帽,安全的做法是釋放后將對(duì)象重新置為nil杂伟,使它成為一個(gè)空指針

29. 向一個(gè)nill對(duì)象發(fā)送消息會(huì)發(fā)生什么?

  • OC中向nil發(fā)消息仍翰,什么都不會(huì)方式,程序是不會(huì)崩潰的赫粥。
  • 因?yàn)镺C的函數(shù)都是通過objc_msgSend進(jìn)行消息發(fā)送來實(shí)現(xiàn)的,相對(duì)于C和C++來說予借,對(duì)于空指針的操作會(huì)引起crash問題越平,而objc_msgSend會(huì)通過判斷self來決定是否發(fā)送消息频蛔,如果self為nil,那么selector也會(huì)為空秦叛,直接返回晦溪,不會(huì)出現(xiàn)問題。視方法返回值挣跋,向nil發(fā)消息可能會(huì)返回nil(返回值為對(duì)象)三圆,0(返回值為一些基礎(chǔ)數(shù)據(jù))或0X0(返回值為id)等。但對(duì)于[NSNull null]對(duì)象發(fā)送消息時(shí)浆劲,是會(huì)crash的嫌术,因?yàn)镹SNull類只有一個(gè)null方法

30. 代碼打印結(jié)果:

@interface Person : NSObject
@end
@implementation Person
@end

@interface Student : Person
@end
@implementation Student
- (instancetype)init{
    if (self= [super init]) {
        NSLog(@"%@", [self class]);
        NSLog(@"%@", [super class]);
        NSLog(@"%@", [self superclass]);
        NSLog(@"%@", [super superclass]);
    }
}
[self class] 和 [super class] 都是給當(dāng)前類返送消息,spuer 表示在父類中查找
[self superClass]  和 [super superclass] 也是也當(dāng)前類發(fā)消息,返回父類
第一個(gè)打印:
Student / Student/ Person / Person

31. 代碼運(yùn)行結(jié)果?

BOOL res1 = [[NSObject class] isKindOfClass:[NSObject class]];
BOOL res2 = [[NSObject class] isMemberOfClass:[NSObject class]];
BOOL res3 = [[Person class] isKindOfClass:[Person class]];
BOOL res4 = [[Person class] isMemberOfClass:[Person class]];
NSLog(@"%d-%d-%d-%d",res1, res2, res3, res4);

  • isKindOfClass 表示對(duì)象是否為當(dāng)前類或者子類的 類型
  • isMemberOfClass 表示是否為當(dāng)前類的的類型
  • isMemberOfClass 分為- 對(duì)象方法 和+ 類方法2中
    - (bool)isMemberOfClass; 比較的是類對(duì)象
    + (bool)isMemberOfClass; 比較的是元類

打印結(jié)果: 1 ,0, 0, 0


精選全網(wǎng) · iOS面試題答案PDF文集

image
  • 獲取加小編的iOS技術(shù)交流圈:130 595 548,直接獲取

32. 講講 RunLoop牌借,項(xiàng)目中有用到嗎度气?

  • runloop運(yùn)行循環(huán),保證程序一直運(yùn)行,主線程默認(rèn)開啟
  • 用于處理線程上的各種事件,定時(shí)器等
  • 可以提高程序性能,節(jié)約CPU資源,有事情做就做,沒事情做就讓線程休眠
  • 應(yīng)用范疇:
    定時(shí)器,事件響應(yīng),手勢識(shí)別,界面刷新,以及autoreleasePool 等等

33. runloop內(nèi)部實(shí)現(xiàn)邏輯?

  • 實(shí)際上 RunLoop 就是這樣一個(gè)函數(shù)膨报,其內(nèi)部是一個(gè) do-while 循環(huán)磷籍。當(dāng)你調(diào)用 CFRunLoopRun() 時(shí),線程就會(huì)一直停留在這個(gè)循環(huán)里现柠;直到超時(shí)或被手動(dòng)停止院领,該函數(shù)才會(huì)返回。

34. runloop和線程的關(guān)系够吩?

  • 每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象
  • RunLoop保存在一個(gè)全局的Dictionary里比然,線程作為key,RunLoop作為value
  • 線程剛創(chuàng)建時(shí)并沒有RunLoop對(duì)象周循,RunLoop會(huì)在第一次獲取它時(shí)創(chuàng)建
  • RunLoop會(huì)在線程結(jié)束時(shí)銷毀
  • 主線程的RunLoop已經(jīng)自動(dòng)獲惹糠ā(創(chuàng)建),子線程默認(rèn)沒有開啟RunLoop

35. timer 與 runloop 的關(guān)系湾笛?

  • timer 定時(shí)器,是基于 runloop 來實(shí)現(xiàn)的, runloop 在運(yùn)行循環(huán)當(dāng)中,監(jiān)聽到了定制器 就會(huì)執(zhí)行;所以 timer 需要添加到 runloop 中去, 注意子線程的 runloop 默認(rèn)是不開啟的,如果在子線程執(zhí)行 timer 需要手動(dòng)開啟 runloop

36. 程序中添加每3秒響應(yīng)一次的NSTimer饮怯,當(dāng)拖動(dòng)tableview時(shí)timer可能無法響應(yīng)要怎么解決?

  • 將 timer 對(duì)象添加到 runloop 中,并修改 runloop 的運(yùn)行 mode
 NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:nil];
 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

37. runloop的mode作用是什么嚎研?

runloop 只能在一種 mode 下運(yùn)行, 做不同的事情,runloop 會(huì)切換到對(duì)應(yīng)的 model 下來執(zhí)行,默認(rèn)是 kCFRunLoopDefaultMode 如果視圖滑動(dòng)再回切換到 UITrackingRunLoopMode,如果需要在多種 mode 下運(yùn)行則需要手動(dòng)設(shè)置 kCFRunLoopCommonModes;

  1. kCFRunLoopDefaultMode:App的默認(rèn)Mode蓖墅,通常主線程是在這個(gè)Mode下運(yùn)行
  2. UITrackingRunLoopMode:界面跟蹤 Mode,用于 ScrollView 追蹤觸摸滑動(dòng)临扮,保證界面滑動(dòng)時(shí)不受其他 Mode 影響
  3. UIInitializationRunLoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode论矾,啟動(dòng)完成后就不再使用,會(huì)切換到kCFRunLoopDefaultMode
  4. GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode杆勇,通常用不到
  5. kCFRunLoopCommonModes: 這是一個(gè)占位用的Mode贪壳,作為標(biāo)記kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并不是一種真正的Mode

38. 使用method swizzling要注意什么?

  1. 方式無限循環(huán)
  2. 進(jìn)行版本迭代的時(shí)候需要進(jìn)行一些檢驗(yàn)靶橱,防止系統(tǒng)庫的函數(shù)發(fā)生了變化

39. 一個(gè)系統(tǒng)方法被 多次交換,會(huì)有什么影響嗎?以及調(diào)用順序?原理

都會(huì)執(zhí)行,后交換的會(huì)先調(diào)用.

第一次交換   viewwillAppAppear 和 test1 的指向的方法實(shí)現(xiàn)地址發(fā)生變化
第二次交換   viewwillAppAppear 和 test2 實(shí)際上等于是 test2 和 test1 進(jìn)行了交換,因?yàn)?viewwillAppAppear 已經(jīng)變?yōu)榱?test1了.

調(diào)用 --> viewwillAppAppear
實(shí)際調(diào)用順序 -->test2--->test1-->viewwillAppAppear
形成一個(gè)閉環(huán):viewwillAppAppear 也只會(huì)調(diào)用一次

40. runloop 主線程監(jiān)聽卡頓

  • 用戶層面感知的卡頓都是來自處理所有UI的主線程上寥袭,包括在主線程上進(jìn)行的大計(jì)算路捧,大量的IO操作,或者比較重的繪制工作传黄。
  • 如何監(jiān)控主線程呢杰扫,首先需要知道的是主線程和其它線程一樣都是靠NSRunLoop來驅(qū)動(dòng)的”礻可以先看看CFRunLoopRun的大概的邏輯 ,不難發(fā)現(xiàn)NSRunLoop調(diào)用方法主要就是在kCFRunLoopBeforeSources和kCFRunLoopBeforeWaiting之間,還有kCFRunLoopAfterWaiting之后,也就是如果我們發(fā)現(xiàn)這兩個(gè)時(shí)間內(nèi)耗時(shí)太長,那么就可以判定出此時(shí)主線程卡頓.只需要另外再開啟一個(gè)線程,實(shí)時(shí)計(jì)算這兩個(gè)狀態(tài)區(qū)域之間的耗時(shí)是否到達(dá)某個(gè)閥值,便能揪出這些性能殺手.
  • 用GCD里的dispatch_semaphore_t開啟一個(gè)新線程章姓,設(shè)置一個(gè)極限值和出現(xiàn)次數(shù)的值,然后獲取主線程上在kCFRunLoopBeforeSources到kCFRunLoopBeforeWaiting再到kCFRunLoopAfterWaiting兩個(gè)狀態(tài)之間的超過了極限值和出現(xiàn)次數(shù)的場景识埋,將堆棧dump下來凡伊,最后發(fā)到服務(wù)器做收集,通過堆棧能夠找到對(duì)應(yīng)出問題的那個(gè)方法窒舟。
- (void)start
{
    if (observer)
        return;

    // // 創(chuàng)建信號(hào)
    semaphore = dispatch_semaphore_create(0);

    // 注冊(cè)RunLoop狀態(tài)觀察
    CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
    observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                       kCFRunLoopAllActivities,
                                       YES,
                                       0,
                                       &runLoopObserverCallBack,
                                       &context);
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);

    // 在子線程監(jiān)控時(shí)長
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (YES)
        {
            // 假定連續(xù)5次超時(shí)50ms認(rèn)為卡頓(當(dāng)然也包含了單次超時(shí)250ms)
            long st = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 50*NSEC_PER_MSEC));
            // Returns zero on success, or non-zero if the timeout occurred.
            if (st != 0)
            {
                if (!observer)
                {
                    timeoutCount = 0;
                    semaphore = 0;
                    activity = 0;
                    return;
                }

                // kCFRunLoopBeforeSources 即將處理source kCFRunLoopAfterWaiting 剛從睡眠中喚醒
                // RunLoop會(huì)一直循環(huán)檢測系忙,從線程start到線程end,檢測檢測到事件源(CFRunLoopSourceRef)執(zhí)行處理函數(shù)惠豺,首先會(huì)產(chǎn)生通知银还,corefunction向線程添加runloopObservers來監(jiān)聽事件,并控制NSRunLoop里面線程的執(zhí)行和休眠洁墙,在有事情做的時(shí)候使當(dāng)前NSRunLoop控制的線程工作蛹疯,沒有事情做讓當(dāng)前NSRunLoop的控制的線程休眠。

                if (activity == kCFRunLoopBeforeSources || activity == kCFRunLoopAfterWaiting)
                {

                    if (++timeoutCount < 3)
                        continue;

                     NSLog(@"有點(diǎn)兒卡");
                }
            }
            timeoutCount = 0;
        }
    });
}

41. _objc_msgForward 函數(shù)是做什么的?直接 調(diào)用它將會(huì)發(fā)生什么?

  • _objc_msgForward 是 IMP 類型热监,用于消息轉(zhuǎn)發(fā)的:當(dāng)向一個(gè)對(duì)象發(fā)送一條消息捺弦,但 它并沒有實(shí)現(xiàn)的時(shí)候,_objc_msgForward 會(huì)嘗試做消息轉(zhuǎn)發(fā)
  • 直接調(diào)用_objc_msgForward 是非常危險(xiǎn)的事孝扛,這是把雙刃刀列吼,如果用不好會(huì)直接 導(dǎo)致程序 Crash,但是如果用得好疗琉,能做很多非掣曰叮酷的事
  • JSPatch 就是直接調(diào)用_objc_msgForward 來實(shí)現(xiàn)其核心功能的

42. 如何打印一個(gè)類中的所有實(shí)例變量

OC的類實(shí)際上是一個(gè)objc_class類型的結(jié)構(gòu)體,包含了實(shí)例變量列表: (objc_ivar_list),可以通過 runtime 函數(shù)來獲取這個(gè)列表:
OBJC_EXPORT Ivar _Nonnull * _Nullable class_copyIvarList(Class _Nullable cls, unsigned int * _Nullable outCount)

例子:

Student *stu = [[Student alloc]init];
stu.stu_name = @"alex";
stu.stu_age = 10;

unsigned int count = 0;
Ivar *list = class_copyIvarList([stu class], &count);
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
for (int i = 0; i< count; i++){
    id iVarName = [NSString stringWithUTF8String:ivar_getName(list[i])];
    dict[iVarName] = [stu valueForKey:iVarName];
}

NSLog(@"%@",dict);

43. 如何使用 rumtime 動(dòng)態(tài)添加一個(gè)類

runtime 很強(qiáng)大.可以動(dòng)態(tài)的創(chuàng)建一個(gè)全新的類或?qū)ο?/p>

// 添加一個(gè)繼承NSObject的類 類名是MyClass
Class MyClass = objc_allocateClassPair([NSObject class], "MyClass", 0);
// 增加實(shí)例變量
class_addIvar(MyClass, "_age", sizeof(NSString *), 0, "@");
//注冊(cè)這個(gè)類到runtime系統(tǒng)中就可以使用他了
objc_registerClassPair(MyClass);
//生成了一個(gè)實(shí)例化對(duì)象
id myobj = [[MyClass alloc] init];
//給剛剛添加的變量賦值
[myobj setValue:@30 forKey:@"age"];
// 打印
NSLog(@"age= %@",[myobj valueForKey:@"age"]);


結(jié)語

再次說一聲歉铝,對(duì)于答案盈简,不一定都合適,歡迎大家積極討論太示;整理不易柠贤,如果您覺得還不錯(cuò),麻煩在文末 “點(diǎn)個(gè)贊” 类缤,或者留下您的評(píng)論“Mark” 一下臼勉,謝謝您的支持

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市餐弱,隨后出現(xiàn)的幾起案子宴霸,更是在濱河造成了極大的恐慌囱晴,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓢谢,死亡現(xiàn)場離奇詭異畸写,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)氓扛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門枯芬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人采郎,你說我怎么就攤上這事千所。” “怎么了蒜埋?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵淫痰,是天一觀的道長。 經(jīng)常有香客問我整份,道長黑界,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任皂林,我火速辦了婚禮朗鸠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘础倍。我一直安慰自己烛占,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布沟启。 她就那樣靜靜地躺著忆家,像睡著了一般。 火紅的嫁衣襯著肌膚如雪德迹。 梳的紋絲不亂的頭發(fā)上芽卿,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音胳搞,去河邊找鬼卸例。 笑死,一個(gè)胖子當(dāng)著我的面吹牛肌毅,可吹牛的內(nèi)容都是我干的筷转。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼悬而,長吁一口氣:“原來是場噩夢啊……” “哼呜舒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起笨奠,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤袭蝗,失蹤者是張志新(化名)和其女友劉穎唤殴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體到腥,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡眨八,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了左电。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廉侧。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖篓足,靈堂內(nèi)的尸體忽然破棺而出段誊,到底是詐尸還是另有隱情,我是刑警寧澤栈拖,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布连舍,位于F島的核電站,受9級(jí)特大地震影響涩哟,放射性物質(zhì)發(fā)生泄漏索赏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一贴彼、第九天 我趴在偏房一處隱蔽的房頂上張望潜腻。 院中可真熱鬧,春花似錦器仗、人聲如沸融涣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽威鹿。三九已至,卻和暖如春轨香,著一層夾襖步出監(jiān)牢的瞬間忽你,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工臂容, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留科雳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓策橘,卻偏偏與公主長得像炸渡,于是被迫代替她去往敵國和親娜亿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丽已,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友买决。感恩相遇沛婴!感恩不離不棄吼畏。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,556評(píng)論 0 11
  • 彩排完嘁灯,天已黑
    劉凱書法閱讀 4,197評(píng)論 1 3
  • 表情是什么泻蚊,我認(rèn)為表情就是表現(xiàn)出來的情緒。表情可以傳達(dá)很多信息丑婿。高興了當(dāng)然就笑了性雄,難過就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 124,435評(píng)論 2 7