MST

星途 面试题库

面试题:Objective-C ARC中循环引用问题及解决办法

请描述在Objective-C的ARC机制下,循环引用是如何产生的,会带来什么问题,并详细说明至少两种常见的解决循环引用的方法,同时给出对应的代码示例。
20.3万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

循环引用的产生

在ARC(自动引用计数)机制下,当两个或多个对象相互强引用时就会产生循环引用。例如,对象A持有对象B的强引用,同时对象B也持有对象A的强引用,这样它们的引用计数都不会降为0,导致内存无法释放。

带来的问题

循环引用会导致对象所占用的内存无法被释放,即使这些对象不再被其他外部对象引用,从而造成内存泄漏,随着程序运行,占用的内存会越来越多,最终可能导致程序性能下降甚至崩溃。

解决循环引用的方法及代码示例

  1. 使用weak修饰符
    • 原理:weak修饰的属性不会增加对象的引用计数,当对象被释放时,指向该对象的weak指针会自动被设置为nil,避免了循环引用。
    • 代码示例
#import <Foundation/Foundation.h>

@interface B;

@interface A : NSObject
@property (nonatomic, strong) B *b;
@end

@interface B : NSObject
@property (nonatomic, weak) A *a; // 使用weak修饰避免循环引用
@end

@implementation A
@end

@implementation B
@end
  1. 使用unsafe_unretained修饰符
    • 原理unsafe_unretained修饰的属性同样不会增加对象的引用计数,但与weak不同的是,当对象被释放时,指向该对象的unsafe_unretained指针不会被自动设置为nil,可能会导致野指针问题,使用时需谨慎。
    • 代码示例
#import <Foundation/Foundation.h>

@interface B;

@interface A : NSObject
@property (nonatomic, strong) B *b;
@end

@interface B : NSObject
@property (nonatomic, unsafe_unretained) A *a; // 使用unsafe_unretained修饰
@end

@implementation A
@end

@implementation B
@end
  1. 在合适的时机打破循环引用
    • 原理:在对象生命周期的适当阶段,手动将其中一个强引用设置为nil,从而打破循环引用。
    • 代码示例
#import <Foundation/Foundation.h>

@interface B;

@interface A : NSObject
@property (nonatomic, strong) B *b;
- (void)dealloc {
    self.b = nil; // 在A的dealloc方法中打破循环引用
    NSLog(@"A dealloc");
}
@end

@interface B : NSObject
@property (nonatomic, strong) A *a;
- (void)dealloc {
    NSLog(@"B dealloc");
}
@end

@implementation A
@end

@implementation B
@end

在使用此方法时,需要确保在合适的时机调用将强引用设置为nil的操作,否则可能达不到预期效果。