MST

星途 面试题库

面试题:Objective-C MRC下复杂对象关系中的引用计数处理

在MRC模式下,有两个类`ClassA`和`ClassB`,`ClassA`中有一个`ClassB`类型的属性,`ClassB`中有一个`NSArray`,数组中存放多个`ClassA`对象。请描述这种情况下如何正确管理对象的引用计数,避免内存泄漏和悬空指针,并给出关键代码片段说明。
33.0万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试
  1. 分析循环引用问题
    • 在这种情况下,ClassA持有ClassB的引用,而ClassBNSArray又持有多个ClassA对象的引用,形成了循环引用。在MRC(Manual Reference Counting)模式下,如果不妥善处理,会导致内存泄漏。
  2. 解决方法
    • 打破循环引用的关键在于将其中一端的引用设置为非强引用。通常建议将ClassBNSArrayClassA对象的引用设置为非强引用(如assign)。因为NSArray本身通过引用计数来管理其内容,将对ClassA的引用设置为非强引用可以避免循环引用。
  3. 关键代码片段
    • ClassA.h
#import <Foundation/Foundation.h>
@class ClassB;

@interface ClassA : NSObject
@property (nonatomic, strong) ClassB *classBProperty;
@end
  • ClassA.m
#import "ClassA.h"
#import "ClassB.h"

@implementation ClassA
- (void)dealloc {
    NSLog(@"ClassA deallocated");
    [super dealloc];
}
@end
  • ClassB.h
#import <Foundation/Foundation.h>
@class ClassA;

@interface ClassB : NSObject
@property (nonatomic, strong) NSArray *classAArray;
@end
  • ClassB.m
#import "ClassB.h"
#import "ClassA.h"

@implementation ClassB
- (void)dealloc {
    NSLog(@"ClassB deallocated");
    [super dealloc];
}
@end
  • 使用示例
#import <Foundation/Foundation.h>
#import "ClassA.h"
#import "ClassB.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ClassA *a = [[ClassA alloc] init];
        ClassB *b = [[ClassB alloc] init];
        NSMutableArray *array = [NSMutableArray array];
        [array addObject:a];
        b.classAArray = array;
        a.classBProperty = b;

        [a release];
        [b release];
    }
    return 0;
}

在这个示例中,ClassB中的classAArrayClassA对象是强引用,但如果不处理循环引用,对象无法正常释放。通过将ClassB中对ClassA的引用改为assign类型(在MRC下手动管理引用计数时打破循环引用的一种方式),可以确保对象在不再被需要时能正确释放内存,避免内存泄漏。例如,可以修改ClassB.h如下:

#import <Foundation/Foundation.h>
@class ClassA;

@interface ClassB : NSObject
@property (nonatomic, strong) NSMutableArray *classAArray;
@end

并在使用时,将添加到数组中的ClassA对象设置为assign类型的包装对象(这里简化示例未详细展示这部分复杂实现,实际可能需要自定义一个包含assign类型ClassA属性的类来包装),从而打破循环引用。

dealloc方法中打印日志是为了观察对象的释放情况。在实际代码中,要确保在对象生命周期结束时,通过release方法正确减少对象的引用计数,以避免内存泄漏。