面试题答案
一键面试循环引用的产生
在ARC(自动引用计数)机制下,当两个或多个对象相互强引用时就会产生循环引用。例如,对象A持有对象B的强引用,同时对象B也持有对象A的强引用,这样它们的引用计数都不会降为0,导致内存无法释放。
带来的问题
循环引用会导致对象所占用的内存无法被释放,即使这些对象不再被其他外部对象引用,从而造成内存泄漏,随着程序运行,占用的内存会越来越多,最终可能导致程序性能下降甚至崩溃。
解决循环引用的方法及代码示例
- 使用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
- 使用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
- 在合适的时机打破循环引用:
- 原理:在对象生命周期的适当阶段,手动将其中一个强引用设置为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的操作,否则可能达不到预期效果。