面试题答案
一键面试KVC底层实现机制
- KVC查找路径
- 当通过KVC访问对象属性时,例如
[person valueForKey:@"name"]
,首先会按照以下顺序查找:- 直接访问实例变量:如果对象有一个名为
_name
(下划线开头的实例变量名),会直接访问该实例变量获取值。 - 访问属性的getter方法:如果没有找到合适的实例变量,会查找
name
属性对应的name
或isName
(对于布尔类型属性)的getter方法。如果存在,则调用该方法获取值。 - 动态方法解析:如果上述两种方式都没有找到,会进入动态方法解析阶段。运行时系统会查找是否有
+ (BOOL)resolveInstanceMethod:(SEL)sel
方法,若实现了该方法且能动态添加所需的方法(如name
方法),则调用该动态添加的方法获取值。 - 备用接收者:如果动态方法解析也未找到,会调用
- (id)forwardingTargetForSelector:(SEL)aSelector
方法,尝试找到其他对象来处理这个消息。 - 完整的消息转发:如果备用接收者也未找到合适的处理对象,会进入完整的消息转发流程,包括
- (void)forwardInvocation:(NSInvocation *)anInvocation
等方法来处理消息。
- 直接访问实例变量:如果对象有一个名为
- 当通过KVC访问对象属性时,例如
- 动态解析
- 动态方法解析:在运行时,类可以通过
+ (BOOL)resolveInstanceMethod:(SEL)sel
方法动态添加方法实现。比如,在KVC访问属性时,如果没有直接的实例变量或getter方法,系统会询问类是否可以动态添加一个方法来响应这个属性访问。 - 备用接收者:
- (id)forwardingTargetForSelector:(SEL)aSelector
方法允许对象指定另一个对象来处理未识别的选择器。在KVC场景下,如果当前对象无法处理某个属性访问,可以返回另一个能处理该属性的对象。 - 完整的消息转发:
- (void)forwardInvocation:(NSInvocation *)anInvocation
方法提供了最后的机会来处理未识别的消息。可以通过修改NSInvocation
对象来重新定向消息到合适的对象或进行自定义的处理逻辑。
- 动态方法解析:在运行时,类可以通过
性能优化策略
- 直接访问实例变量
- 原理:避免KVC复杂的查找路径,直接访问实例变量的效率更高。在大规模数据处理或频繁KVC操作场景下,通过直接访问实例变量,减少了查找getter方法、动态方法解析等开销。例如,对于一个包含大量数据的自定义类
DataObject
,如果经常需要访问其某个属性dataValue
,可以在代码中直接访问_dataValue
实例变量(前提是访问权限允许)。这样做跳过了KVC查找路径中可能的方法调用和动态解析步骤,提高了访问效率。
- 原理:避免KVC复杂的查找路径,直接访问实例变量的效率更高。在大规模数据处理或频繁KVC操作场景下,通过直接访问实例变量,减少了查找getter方法、动态方法解析等开销。例如,对于一个包含大量数据的自定义类
- 缓存KVC结果
- 原理:对于频繁访问且数据不经常变化的属性,使用缓存可以避免重复的KVC操作。在大规模数据处理时,可能会多次访问某个对象的特定属性,每次通过KVC获取属性值都要经过一系列查找步骤,开销较大。可以在类中添加一个缓存属性,在首次通过KVC获取值后,将其存储在缓存中。后续再次访问时,先检查缓存,若缓存中有值则直接返回,避免重复的KVC操作。例如,在一个包含大量用户信息的应用中,用户的
displayName
属性可能经常被访问且不常变化,可以在用户类中添加一个_cachedDisplayName
缓存变量,在首次获取displayName
时,同时将值存入缓存,后续访问时优先从缓存读取。
- 原理:对于频繁访问且数据不经常变化的属性,使用缓存可以避免重复的KVC操作。在大规模数据处理时,可能会多次访问某个对象的特定属性,每次通过KVC获取属性值都要经过一系列查找步骤,开销较大。可以在类中添加一个缓存属性,在首次通过KVC获取值后,将其存储在缓存中。后续再次访问时,先检查缓存,若缓存中有值则直接返回,避免重复的KVC操作。例如,在一个包含大量用户信息的应用中,用户的
- 减少KVC嵌套深度
- 原理:KVC支持嵌套访问,如
[person valueForKeyPath:@"address.city"]
。但嵌套深度越深,查找路径越复杂,性能开销越大。在大规模数据处理中,尽量减少这种嵌套访问的深度。如果可能,将嵌套结构扁平化,使得属性访问更直接。例如,将复杂的地址结构拆分成单独的属性,person.city
,这样在获取城市信息时,直接通过简单的KVC或直接访问实例变量的方式获取,避免了多层嵌套查找带来的性能损耗。
- 原理:KVC支持嵌套访问,如