在 iOS 开发中,Block 是 Objective-C 和 Swift 中的闭包实现。Block 是一种封装了代码和上下文的对象,可以捕获外部变量并在需要时执行。以下是关于 Block 的类型和存储位置的详细说明:
1. Block 的类型
在 Objective-C 中,Block 可以分为以下几种类型:
1.1 NSGlobalBlock(全局 Block)
-
特点:
- Block 没有捕获任何外部变量。
- 类似于全局函数,存储在全局数据区。
-
示例:
void (^globalBlock)(void) = ^{ NSLog(@"This is a global block."); }; NSLog(@"%@", globalBlock); // 输出: <__NSGlobalBlock__: 0x...>
1.2 NSStackBlock(栈 Block)
-
特点:
- Block 捕获了外部变量,但未逃逸出当前作用域。
- 存储在栈上,生命周期与当前作用域绑定。
-
示例:
int value = 10; void (^stackBlock)(void) = ^{ NSLog(@"Captured value: %d", value); }; NSLog(@"%@", stackBlock); // 输出: <__NSStackBlock__: 0x...>
1.3 NSMallocBlock(堆 Block)
-
特点:
- Block 捕获了外部变量,并且逃逸出当前作用域(例如被复制到堆上)。
- 存储在堆上,由 ARC 管理内存。
-
示例:
int value = 10; void (^heapBlock)(void) = [^{ NSLog(@"Captured value: %d", value); } copy]; NSLog(@"%@", heapBlock); // 输出: <__NSMallocBlock__: 0x...>
2. Block 的存储位置
Block 的存储位置取决于其类型和捕获的变量:
2.1 全局数据区
- NSGlobalBlock 存储在全局数据区。
- 这种 Block 不捕获任何外部变量,类似于全局函数。
2.2 栈
- NSStackBlock 存储在栈上。
- 这种 Block 捕获了外部变量,但未逃逸出当前作用域。
2.3 堆
- NSMallocBlock 存储在堆上。
- 这种 Block 捕获了外部变量,并且逃逸出当前作用域(例如被复制到堆上)。
3. Block 的内存管理
- NSGlobalBlock 和 NSStackBlock 不需要手动管理内存。
- NSMallocBlock 由 ARC 自动管理内存,开发者无需手动释放。
4. Block 的逃逸与非逃逸
- 非逃逸 Block:Block 在函数返回前执行完毕,通常分配在栈上。
- 逃逸 Block:Block 被存储或传递到函数外部,通常分配在堆上。
5. Swift 中的闭包
在 Swift 中,闭包的行为与 Objective-C 的 Block 类似:
- 非逃逸闭包:默认情况下,函数参数中的闭包是非逃逸的。
-
逃逸闭包:使用
@escaping
标记的闭包是逃逸的,通常分配在堆上。
总结
- Block 类型:NSGlobalBlock、NSStackBlock、NSMallocBlock。
- 存储位置:全局数据区、栈、堆。
- 内存管理:NSMallocBlock 由 ARC 管理,其他类型无需手动管理。
- Swift 闭包:行为与 Block 类似,逃逸闭包分配在堆上。
如果你有更多问题,欢迎继续提问!