MST

星途 面试题库

面试题:Objective-C协议的深层次理解与内存管理

当在协议中定义属性时,属性的内存管理规则是怎样的?如果协议被多个类遵循,且这些类对协议属性的内存管理策略不同,会带来什么问题以及如何解决?请结合ARC(自动引用计数)和MRC(手动引用计数)两种环境进行分析。
23.5万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

协议中属性内存管理规则

  1. ARC环境
    • 在协议中定义属性时,通常使用nonatomic修饰,因为atomic属性会带来性能开销。对于属性的内存管理特性,常用strongweak
    • 如果使用strong,遵循协议的类在设置属性值时,会强引用该对象,增加其引用计数。例如,协议定义@property (nonatomic, strong) id myObject;,当遵循该协议的类设置self.myObject = someObject;时,someObject的引用计数会增加。
    • 如果使用weak,遵循协议的类设置属性值时,不会增加对象的引用计数,主要用于避免循环引用。比如在视图控制器之间传递数据时,父视图控制器持有子视图控制器,子视图控制器通过协议属性反向引用父视图控制器,使用weak可以防止循环引用。
  2. MRC环境
    • 同样一般使用nonatomic。属性内存管理特性有retainassign等。
    • retain类似于ARC中的strong,当遵循协议的类设置属性值时,会发送retain消息,增加对象的引用计数。例如@property (nonatomic, retain) id myObject;self.myObject = someObject;时,someObject引用计数加1。
    • assign则不会改变对象的引用计数,一般用于基本数据类型,如NSIntegerCGFloat等,也可用于对象类型,但要注意对象释放后指针成为野指针的问题。

多类遵循协议且内存管理策略不同带来的问题

  1. ARC环境
    • 循环引用问题:如果不同类对协议属性使用了不恰当的内存管理策略,可能导致循环引用。比如类A和类B都遵循同一协议,类A将协议属性设为strong引用类B实例,类B又将协议属性设为strong引用类A实例,这样就形成了循环引用,导致对象无法释放。
    • 内存泄漏:如果一个类对协议属性过度强引用,而其他类期望属性是弱引用,可能导致对象不能及时释放,造成内存泄漏。
  2. MRC环境
    • 过度释放问题:如果不同类对协议属性的内存管理策略不一致,可能会出现过度释放的情况。例如,一个类认为自己拥有对象的所有权(通过retain),而另一个类在不知情的情况下释放了该对象,当第一个类再次访问对象时就会导致程序崩溃(野指针访问)。
    • 内存泄漏:与ARC类似,如果类对协议属性过度retain,而没有正确释放,就会导致内存泄漏。

解决方法

  1. ARC环境
    • 明确内存管理规则:在协议文档中清晰地说明属性的推荐内存管理策略,比如明确指出对于某个协议属性应该使用weak以避免循环引用。
    • 代码审查:通过代码审查确保所有遵循协议的类都遵循统一的内存管理策略,避免出现不恰当的strong引用。
    • 使用中间对象或代理:如果存在潜在的循环引用,可以引入中间对象或代理对象来打破循环。例如,使用一个独立的视图模型类来管理数据,视图控制器通过协议与视图模型交互,避免视图控制器之间直接循环引用。
  2. MRC环境
    • 制定规范:制定严格的内存管理规范,明确每个遵循协议的类在设置和释放协议属性时的责任。例如,规定某个类在设置协议属性时负责retain,其他类在获取属性后不负责释放等。
    • 引用计数跟踪工具:使用工具来跟踪对象的引用计数,例如NSZombieEnabled(在调试时),可以帮助发现过度释放或未释放的问题。
    • 采用设计模式:例如使用观察者模式,一个对象观察另一个对象的状态变化,而不是直接持有强引用,从而避免循环引用和过度释放问题。