MST

星途 面试题库

面试题:Objective-C中KVC与KVO在运行时交互及应用场景优化

请深入分析Objective-C中KVC与KVO在运行时是如何交互的。在实际开发场景中,针对复杂数据模型,怎样利用KVC和KVO的特性进行优化,以提高代码的性能和可维护性,并举例说明。
10.9万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

KVC 与 KVO 在运行时的交互分析

  1. KVC(Key - Value Coding)原理
    • KVC是一种通过键来访问对象属性的机制。当使用valueForKey:方法时,运行时系统会按照特定的搜索模式查找对应的属性。首先会查找对象的get<Key>is<Key>方法,如果不存在则查找_<key><key>实例变量。如果都未找到,会调用accessInstanceVariablesDirectly方法,若该方法返回YES,则继续搜索实例变量。若最终都未找到,会调用valueForUndefinedKey:方法,默认实现会抛出异常。
    • 对于setValue:forKey:方法,首先会查找set<Key>:方法,如果不存在则同样遵循类似的查找实例变量的规则,最后若都未找到会调用setValue:forUndefinedKey:方法,默认实现也会抛出异常。
  2. KVO(Key - Value Observing)原理
    • KVO基于观察者模式。当一个对象(被观察对象)的属性值发生变化时,会通知所有注册的观察者对象。实现机制是通过运行时动态创建被观察对象的子类,并重写被观察属性的setter方法。在setter方法中,会调用willChangeValueForKey:didChangeValueForKey:方法,这两个方法会通知观察者属性值即将改变和已经改变。
  3. 交互分析
    • KVO依赖KVC来获取和设置属性值。当使用KVO观察一个属性时,KVO通过KVC机制来访问属性的值。例如,当观察对象的某个属性变化时,KVO在通知观察者前,需要通过KVC获取属性的新值。同时,KVO通知观察者时传递的信息,也是基于KVC对属性的访问和变化感知。

复杂数据模型中利用 KVC 和 KVO 特性优化代码

  1. 提高性能
    • 减少不必要的观察:在复杂数据模型中,避免对所有属性都设置KVO观察。只对关键业务相关且会频繁变化的属性设置观察。例如,在一个电商应用中,商品的库存属性频繁变化且与业务紧密相关,而商品的描述属性很少变化,可以只对库存属性设置KVO观察。
    • 批量处理变化:利用KVC的集合操作特性,当多个相关属性变化时,通过KVC的集合操作一次性处理,而不是每次属性变化都触发KVO通知。比如,有一个包含多个商品价格的数组,可以使用KVC的@sum操作一次性计算总价,而不是对每个商品价格设置KVO观察并分别计算总价。
  2. 提高可维护性
    • 分层管理数据模型:将复杂数据模型分层,使用KVC的嵌套键路径来访问深层属性。例如,有一个包含用户信息的复杂模型,用户有地址信息,地址又有城市信息。可以通过user.valueForKeyPath:@"address.city"来访问城市信息,使代码结构更清晰。
    • 使用KVO进行解耦:在不同模块之间,通过KVO进行通信,减少模块间的直接依赖。例如,一个模块负责数据的获取和更新,另一个模块负责UI展示。数据模块通过KVO通知UI模块数据的变化,UI模块根据通知更新界面,这样两个模块之间的耦合度降低,代码更易维护。

举例说明

假设我们有一个复杂数据模型,一个Order类包含多个Product对象,Product类有pricequantity属性,Order类需要计算订单总价。

  1. 代码实现
    // Product.h
    @interface Product : NSObject
    @property (nonatomic, assign) CGFloat price;
    @property (nonatomic, assign) NSInteger quantity;
    @end
    
    // Product.m
    @implementation Product
    @end
    
    // Order.h
    @interface Order : NSObject
    @property (nonatomic, strong) NSMutableArray<Product *> *products;
    @property (nonatomic, assign) CGFloat totalPrice;
    - (void)updateTotalPrice;
    @end
    
    // Order.m
    @implementation Order
    - (void)updateTotalPrice {
        NSArray *prices = [self.products valueForKeyPath:@"price"];
        NSArray *quantities = [self.products valueForKeyPath:@"quantity"];
        NSNumber *sumOfPrices = [prices valueForKeyPath:@"@sum.self"];
        NSNumber *sumOfQuantities = [quantities valueForKeyPath:@"@sum.self"];
        self.totalPrice = [sumOfPrices floatValue] * [sumOfQuantities floatValue];
    }
    @end
    
    • 在这个例子中,Order类通过KVC的集合操作计算订单总价,提高了性能。同时,若Productpricequantity属性变化,可以通过在Product类对这些属性设置KVO观察,在Order类的观察方法中调用updateTotalPrice方法来更新总价,实现了不同模块(ProductOrder)之间的解耦,提高了可维护性。