MST

星途 面试题库

面试题:深入探究Objective-C关联对象的实现原理及优化

详细阐述Objective-C关联对象(Associated Object)的底层实现原理,包括但不限于runtime如何存储和管理关联对象。基于其实现原理,思考在大型项目中,如何对关联对象的使用进行优化,以提高程序的性能和稳定性?
48.2万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

Objective - C关联对象底层实现原理

  1. 存储结构
    • 在Objective - C中,关联对象是通过objc_object结构体中的一个isa指针指向类的元数据,类的元数据中包含了关联对象的信息。关联对象实际上是存储在一个全局的哈希表(AssociationsManager管理的AssociationsHashMap)中。
    • 这个哈希表的键是对象的内存地址(也就是对象的isa指针指向的地址),值是另一个哈希表(ObjectAssociationMap),在ObjectAssociationMap中,键是关联对象的key(通常是一个NSStringvoid*类型),值是关联对象的Association结构体,Association结构体中包含了关联对象以及关联策略等信息。
  2. 关联策略
    • 关联对象有几种关联策略,如OBJC_ASSOCIATION_ASSIGN(弱引用)、OBJC_ASSOCIATION_RETAIN_NONATOMIC(非原子性强引用)、OBJC_ASSOCIATION_COPY_NONATOMIC(非原子性拷贝)、OBJC_ASSOCIATION_RETAIN(原子性强引用)、OBJC_ASSOCIATION_COPY(原子性拷贝)。这些策略决定了关联对象的生命周期管理。例如,OBJC_ASSOCIATION_ASSIGN类似属性的assign,不会增加对象的引用计数,适用于避免循环引用的场景;而OBJC_ASSOCIATION_RETAIN会增加对象的引用计数,确保关联对象在主对象存在期间不会被释放。
  3. runtime操作
    • 当使用objc_setAssociatedObject函数设置关联对象时,runtime首先会获取当前对象的关联对象哈希表(如果不存在则创建)。然后根据传入的keyvalue以及关联策略,在哈希表中插入或更新相应的关联对象。
    • 当使用objc_getAssociatedObject函数获取关联对象时,runtime会根据对象的内存地址找到对应的关联对象哈希表,再根据传入的key从哈希表中查找并返回关联对象。
    • 当对象被释放时,runtime会遍历其关联对象哈希表,根据关联策略释放相应的关联对象。例如,如果是强引用策略,会释放关联对象;如果是弱引用策略,不会对关联对象做任何操作。

大型项目中关联对象使用的优化

  1. 减少不必要的关联对象
    • 在大型项目中,仔细评估是否真的需要使用关联对象。如果可以通过其他方式(如继承、组合等)来实现相同的功能,优先选择这些方式。因为关联对象的存储和管理会增加内存开销和runtime操作的成本。例如,对于一些简单的属性添加需求,可以通过子类化来添加属性,而不是使用关联对象。
  2. 合理选择关联策略
    • 根据业务场景选择合适的关联策略。如果存在循环引用的风险,优先选择OBJC_ASSOCIATION_ASSIGN策略。例如,在视图控制器和其关联的视图之间,如果视图控制器持有视图的强引用,视图又通过关联对象持有视图控制器,就可能产生循环引用,此时视图对视图控制器的关联可以使用OBJC_ASSOCIATION_ASSIGN。如果需要确保关联对象在主对象存在期间一直存在,选择OBJC_ASSOCIATION_RETAINOBJC_ASSOCIATION_COPY策略,但要注意避免过度引用导致内存泄漏。
  3. 集中管理关联对象
    • 可以创建一个工具类或模块来集中管理关联对象的设置和获取。这样可以减少代码中分散的关联对象操作,提高代码的可维护性。同时,在这个集中管理模块中,可以添加一些日志记录或性能监控代码,便于排查问题和优化性能。例如,记录每次设置和获取关联对象的时间,找出性能瓶颈。
  4. 延迟设置关联对象
    • 如果关联对象的创建和设置成本较高,可以考虑延迟设置。只有在真正需要使用关联对象时才进行设置,而不是在对象初始化时就设置好。这样可以避免在程序启动或对象初始化时不必要的性能开销。例如,对于一些只有在特定用户操作后才会用到的关联对象,可以在用户触发相应操作时再进行设置。