iOS 底层知识总结

一、OC语法

1、OC对象的本质

1)一个NSObject对象占用多少内存?
A:系统分配16个字节给一个NSObject对象(可以通过C函数malloc_size函数获得,通过查看OC源码,alloc函数,也即allocWithZone:中有判断当字节数小于16时就分配16个字节);而一个NSObject对象仅使用8个字节,用于存放成员变量isa指针,(可以通过runtime 的函数class_getInstanceSize获得)
………………..
2)对象的isa指针指向哪里?
instance对象的isa指向class对象
class对象的isa指向meta-class对象
meta-class对象指向基类的meta-class对象
(以上的“指向”实际是通过isa与ISA_MASK常量进行&位运算的结果)

3)OC的类信息存放在哪里?
成员变量、属性、协议、实例方法等信息存放在类对象中;
类方法存放在元类对象中;
另外,成员变量的具体值存放在实例对象中。

2、KVO

1)iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)
当一个对象的属性被监听时,runtime会动态创建一个新的类,这个新的类是原有类的子类(NSKVONotifying_原有类名),对象的isa会指向这个新类的类对象Class。
当修改对象的属性时,会调用 Foundation 中的 _NSSetXXValueAndNotify 函数,
这个函数会调用willChangeValueForKey:, 然后调用原有类的setter以修改属性值,最后调用didChangeValueForKey:, didChangeValueForKey:内部会触发监听器(Observer)的监听方法-observeValueForKeyPath:ofObject:change:contex:

2)如何手动触发KVO?
手动调用被监听对象的willChangeValueForKey:方法,让后调用didChangeValueForKey:方法,两个方法都需要调用,否则不会触发KVO

3)直接修改成员变量会触发KVO吗?
不会。因为不会走setter方法,就不会走触发KVO的流程

3、KVC

1)通过KVC修改属性会触发KVO么?
会触发KVO,因为 setValueForKey:方法会触发willChangeValueForKey: 和 didChangeValueForKey:方法

2)KVC的赋值和取值时怎样的?原理是什么?
赋值:调用setValue:forkey:方法时,会按 -setKey:,-_setKey: 的顺序查找对象的方法,若查到有实现其中的方法,则调用;若都没有实现,则判断 +accessInstanceVariableDirectly 方法的返回值,若为YES,则按 _key, _isKey, key, isKey的顺序查到对象的实例变量,查找到则赋值。若方法没有实现,+accessInstanceVariableDirectly返回NO或者实例变量都不存在,则会调用valueForUndefinedKey:,并报 NSUnknownKeyException 错误。
取值:调用valueForKey: 会按 -getKey, -key, -isKey, -_key的顺序查找方法,若查到有实现其中的方法,则调用并返回值;若都没有实现,则判断 +accessInstanceVariableDirectly 方法的返回值,若为YES,则按 _key, _isKey, key, isKey的顺序查找成员变量,查找到则将成员变量的值返回。若方法没有实现,+accessInstanceVariableDirectly返回NO或者实例变量都不存在,则会调用valueForUndefinedKey:,并报 NSUnknownKeyException 错误。

4、Category

1)Category的使用场合是什么?
给已有的类扩展属性、方法、和协议;
将一个类按照功能拆分为不同的分类,方便管理和阅读代码

2)Category的实现原理
Category在编译完成后的底层结构是 struct category_t 的结构体,结构体中存放着Category数据(类名,属性列表,对象方法列表,类方法列表,协议列表)
在程序运行的时候,通过runtime将Category数据合并到原类的类对象和原类对象中()

4)Category和Class Extension的区别是什么?
Category是在运行时将其中的数据(如方法等)合并到原类中,
而Class Extension是在编译时就将数据合并到原类中

5)Category中有load方法吗?load方法是什么时候调用的?load 方法能继承吗?
·有load方法
·load方法是在runtime加载类、分类时调用的
·load方法可以继承,但一般不会主动调用load方法,而是系统自动调用

6)load、initialize方法的区别什么?它们在category中的调用的顺序?以及出现继承时他们之间的调用过程?
①区别:
调用时刻:
load是runtime加载类、分类时调用(只会调用1次);
initialize时类第1次接受到消息时调用,每个类只会initialize一次(但是子类没有实现initialize方法,则父类的initialize方法可能会调用多次)
调用方式:
load时根据函数地址直接调用;而initialize时通过objc_msgSend调用
②调用顺序
load : a.先调用类的load:先编译的类优先调用load;调用子类的load之前,会先调用父类的load
b.后调用分类的load:先编译的分类优先调用
initialize: a.先初始化父类调用父类initialize
b.再初始化子类,调用子类的initialize(若子类没有实现initialize方法,则最终调用的的是父类的intialize方法)

5、Block

1)block 的原理是怎样的?本质是什么?
block 是封装了函数调用和调用环境的 OC 对象

2)__block 的作用是什么?有什么使用注意点?
作用:被 __block 修饰的 auto 变量(即非全局变量、非 static 变量的局部变量),会被包装成一个 OC 对象(结构体),变量的实际值会作为该结构体的一个成员,这样可以解决在 block 中无法修改 auto 变量的问题。
注意点:内存管理相关,__block 修饰的变量在栈上时,block 不会对其强引用;__block 变量被 copy 到堆上时,在 MRC 下,block 不会对其强引用,在 ARC 下,会根据变量的其他修饰关键字进行强引用或弱引用。

3)block的属性修饰词为什么是 copy?使用block有哪些使用注意?
为什么是 copy:block 没有被 copy 之前,是在内存中的栈上或者全局区,生命周期由系统管理;而 copy 之后会被 copy 到堆上,此时 block 生命周期由代码管理。
使用注意:循环引用问题,会导致内存泄漏。

4)block 在修改 NSMutableArray (添加或移除元素),需不需要添加 __block?
不需要。因为对 NSMutableArray 添加或移除元素不需要修改变量的值。

Runtime

1、消息机制

1)讲一下 OC 的消息机制
OC 对象调用方法底层转为 objc_msgSend 函数调用,即给对象(消息接受者)发送一条消息(selector 方法名);
objc_msgSend 函数底层实现大致分为三大阶段:消息发送,动态方法解析,消息转发;
消息发送:通过对象的 isa 指针找到类对象或元类对象(取决于消息接受者是实例对象还是类对象,这里假设是实例对象,类对象的处理类似),依次在类对象中的方法缓存列表和方法列表中查找消息的 selector 方法名,若找到则直接调用方法,否则继续从父类的方法列表中查找,一直找到基类为止;若查找到基类也没有找到方法,则进入动态方法解析阶段;
动态方法解析:实现 -resolveInstanceMethod:(SEL)sel 方法,并调用 runtime 的方法 class_addMethod,为对象动态地添加一个方法,然后再次进入消息发送阶段,并标记已经尝试过动态方法解析;若添加了方法,则直接调用;若没有添加,则进入消息转发阶段;
消息转发:实现 -forwardingTargetForSelector: 方法,返回一个新的对象做为消息接受者,并调用 objc_msgSend 方法;若没有返回新的对象而是返回 nil,则会调用 -methodSignatureForSelctor: 方法,若此方法返回一个方法签名,则进入 -forwardInvocation: 方法,可以做任何处理;若返回 nil,则会报经典错误 unrecognized selector sent to instance xxxxx

2)消息转发机制流程
同问题1)

3)什么是Runtime?平时项目中有用过么?
Runtime:OC 是一门动态性很强的语言,很多操作允许推迟到程序运行时再执行;
OC 的动态性是由 Runtime 来实现的,Runtime 是一套 C 语言的 API,封装了很多动态性相关的函数;
平时编写的 OC 代码,底层都是转换为了 Runtime 的 API 进行调用。
用途:给分类添加属性实现(关联对象 AssociateObject);
方法交换(method_exchange);
遍历类的所有成员变量(归档解档,获取私有成员如textField._placeholderLabel,字典转模型)
利用消息转发机制,监测方法找不到的问题;
...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,884评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,212评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,351评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,412评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,438评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,127评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,714评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,636评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,173评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,264评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,402评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,073评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,763评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,253评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,382评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,749评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,403评论 2 358