MST

星途 面试题库

面试题:Objective-C内存管理中,如何识别和优化循环引用导致的不必要内存分配?

假设在Objective-C项目中,有两个类A和B,它们相互持有对方的引用,形成了循环引用。请描述这种情况下如何通过弱引用(weak)、无主引用(unowned)等手段打破循环引用,减少不必要的内存分配,并给出相应的代码示例。
39.7万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

在Objective-C中,为了打破类A和类B之间的循环引用,可以使用weak(iOS 5.0及以上)和unowned(ARC环境下类似unsafe_unretained,不会自动置为nil)属性。

  1. 使用weak属性打破循环引用weak属性不会增加对象的引用计数,当被引用的对象释放时,weak属性会自动被设置为nil,从而避免野指针。

假设类A和类B定义如下:

#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

在使用时:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        A *a = [[A alloc] init];
        B *b = [[B alloc] init];
        a.b = b;
        b.a = a;
    } // 当离开自动释放池时,a和b会被正确释放,不会造成内存泄漏
    return 0;
}
  1. 使用unowned属性打破循环引用unowned属性同样不会增加对象的引用计数,但与weak不同的是,当被引用的对象释放后,unowned属性不会自动置为nil,所以使用unowned时要确保被引用对象的生命周期长于引用它的对象,否则会产生野指针。

假设类A和类B定义如下:

#import <Foundation/Foundation.h>

@interface B; // 前向声明

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

@interface B : NSObject
@property (nonatomic, unowned) A *a; // 使用unowned属性
@end

@implementation A
@end

@implementation B
@end

在使用时,要保证对象的生命周期合理性:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        A *a = [[A alloc] init];
        B *b = [[B alloc] init];
        a.b = b;
        b.a = a;
    } // 当离开自动释放池时,如果A先于B释放,b.a会成为野指针,所以使用unowned需谨慎确保A的生命周期长于B
    return 0;
}

一般来说,weak更安全,因为它会自动置nil,而unowned适用于能确保对象生命周期关系的场景,以避免weak带来的额外开销。