MST

星途 面试题库

面试题:Objective-C中Block内存循环引用在ARC下的深度剖析与优化

在ARC(自动引用计数)环境下,假设存在一个视图控制器ViewController,内部有一个属性block和一个对象obj,block中使用了obj,同时obj又持有这个block,这种情况下如何检测和解决内存循环引用?请详细分析ARC机制下的内存管理过程以及可能引发循环引用的细节,并给出优化后的代码示例。
35.9万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

1. 检测内存循环引用

  • ** Instruments工具**:使用Xcode自带的Instruments工具,特别是Leaks模板。运行应用程序,当怀疑有内存泄漏(通常循环引用会导致对象无法释放从而造成内存泄漏)时,暂停Instruments,它会指出可能存在泄漏的对象以及它们之间的引用关系,帮助确定是否存在循环引用。

2. ARC机制下内存管理过程及循环引用细节

  • ARC机制下内存管理过程
    • 在ARC环境下,编译器会自动插入内存管理代码,比如retainreleaseautorelease。当一个对象被创建时,它的引用计数为1。每当有新的强引用指向该对象,引用计数加1;当一个强引用被移除,引用计数减1。当引用计数降为0时,对象的内存被自动释放。
    • 例如,当ViewController创建obj时,ViewControllerobj有一个强引用,obj的引用计数为1。
  • 可能引发循环引用的细节
    • 在给定场景中,ViewControllerblock中使用了obj,默认情况下block会对obj进行强引用,使得obj的引用计数加1。同时,obj又持有这个block,也就是objblock有一个强引用。这样就形成了一个循环:ViewController -> block -> obj -> block。在这个循环中,由于互相强引用,ViewControllerblockobj的引用计数都不会降为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),blockViewController(进而对obj)的引用不再是强引用,打破了循环引用,使得相关对象在不再被其他对象强引用时能够正常释放内存。