MST

星途 面试题库

面试题:Objective-C代码块(Block)的内存特性及应用场景

阐述Objective-C代码块(Block)的内存特性,比如在栈上、堆上的情况以及如何进行内存管理。并举例说明在实际项目开发中,代码块在多线程编程场景下的具体应用,分析不同内存情况对多线程编程的影响。
29.7万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

1. Block的内存特性

  • 栈上(Stack):默认情况下,Block定义在方法内部时,它会在栈上分配内存。栈上的Block生命周期与它所在的函数栈帧相同,当函数返回时,栈上的Block会被销毁。例如:
void someFunction() {
    int value = 10;
    void (^stackBlock)() = ^{
        NSLog(@"Value: %d", value);
    };
    stackBlock();
}

这里的stackBlock就是在栈上的。

  • 堆上(Heap):当Block被copy操作时,它会从栈上复制到堆上。堆上的Block有自己独立的内存空间,其生命周期由引用计数管理。在ARC(自动引用计数)环境下,编译器会自动处理copy操作。例如,将Block作为返回值或者存储在对象的属性中时,通常会进行copy操作到堆上。
@property (nonatomic, copy) void (^heapBlock)();

- (void)setupBlock {
    int value = 20;
    void (^stackBlock)() = ^{
        NSLog(@"Value: %d", value);
    };
    self.heapBlock = stackBlock; // 这里stackBlock被copy到堆上
}

2. 内存管理

  • ARC下:ARC会自动管理Block的内存。当Block被copy到堆上后,ARC会根据引用计数自动释放堆上的Block。例如,当持有堆上Block的对象被释放时,如果没有其他强引用指向该Block,ARC会自动释放它。
  • MRC下:在手动引用计数(MRC)环境中,需要开发者手动进行copyrelease操作。对栈上的Block调用copy,将其复制到堆上并增加引用计数;当不再需要堆上的Block时,调用release减少引用计数,当引用计数为0时,堆上的Block会被释放。

3. 多线程编程场景下的应用

  • GCD(Grand Central Dispatch):GCD是iOS开发中常用的多线程编程模型,大量使用了Block。例如,在主线程以外的队列中执行任务:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
    // 这里的Block会在后台队列中执行
    NSLog(@"This is a background task");
});
  • NSOperationQueue:NSOperationQueue也可以配合Block使用来实现多线程任务。例如:
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
    // 多线程任务代码
    NSLog(@"This is a task in NSOperationQueue");
}];
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue addOperation:blockOperation];

4. 不同内存情况对多线程编程的影响

  • 栈上Block:由于栈上Block生命周期与函数栈帧相同,如果在多线程场景下使用栈上Block,当函数返回,栈上Block被销毁,可能导致多线程任务访问已释放的内存,引发程序崩溃。例如,在函数内部启动一个异步任务并使用栈上Block,函数返回后,栈上Block被销毁,而异步任务可能还未执行完,此时访问Block中的变量就会出错。
  • 堆上Block:堆上的Block由于有独立的内存空间和引用计数管理,在多线程场景下相对安全。只要堆上Block的引用计数不为0,它就不会被释放,多线程任务可以正常执行。例如,在GCD中使用的Block,通常都是在堆上,这样可以确保任务在后台队列中顺利执行,不用担心内存提前释放的问题。