面试题答案
一键面试1. 检测内存循环引用
- ** Instruments工具**:使用Xcode自带的Instruments工具,特别是Leaks模板。运行应用程序,当怀疑有内存泄漏(通常循环引用会导致对象无法释放从而造成内存泄漏)时,暂停Instruments,它会指出可能存在泄漏的对象以及它们之间的引用关系,帮助确定是否存在循环引用。
2. ARC机制下内存管理过程及循环引用细节
- ARC机制下内存管理过程:
- 在ARC环境下,编译器会自动插入内存管理代码,比如
retain
、release
和autorelease
。当一个对象被创建时,它的引用计数为1。每当有新的强引用指向该对象,引用计数加1;当一个强引用被移除,引用计数减1。当引用计数降为0时,对象的内存被自动释放。 - 例如,当
ViewController
创建obj
时,ViewController
对obj
有一个强引用,obj
的引用计数为1。
- 在ARC环境下,编译器会自动插入内存管理代码,比如
- 可能引发循环引用的细节:
- 在给定场景中,
ViewController
的block
中使用了obj
,默认情况下block
会对obj
进行强引用,使得obj
的引用计数加1。同时,obj
又持有这个block
,也就是obj
对block
有一个强引用。这样就形成了一个循环:ViewController -> block -> obj -> block
。在这个循环中,由于互相强引用,ViewController
、block
和obj
的引用计数都不会降为0,从而导致内存无法释放,形成循环引用。
- 在给定场景中,
3. 解决方法及优化后代码示例
- 使用弱引用解决循环引用:
- 在
block
中使用obj
时,通过弱引用的方式来打破循环。在Objective - C中,可以使用__weak
关键字;在Swift中,可以使用weak
关键字。 - Objective - C示例代码:
- 在
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) id obj;
@property (nonatomic, copy) void (^block)(void);
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
// 使用strongSelf来访问obj,防止在block执行过程中self被释放
id obj = strongSelf.obj;
NSLog(@"obj: %@", obj);
}
};
self.obj = [[NSObject alloc] init];
self.obj.block = self.block;
}
@end
- Swift示例代码:
import UIKit
class ViewController: UIViewController {
var obj: AnyObject?
var block: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
weak var weakSelf = self
block = { [weak weakSelf] in
guard let strongSelf = weakSelf else { return }
if let obj = strongSelf.obj {
print("obj: \(obj)")
}
}
obj = NSObject()
(obj as? CustomObject)?.block = block
}
}
class CustomObject {
var block: (() -> Void)?
}
在上述代码中,通过使用弱引用(Objective - C中的__weak
和Swift中的weak
),block
对ViewController
(进而对obj
)的引用不再是强引用,打破了循环引用,使得相关对象在不再被其他对象强引用时能够正常释放内存。