返回
objc 块实现分析
IOS
2023-11-02 22:40:39
作为 iOS 开发中至关重要的组成部分,Block 在各种场景中广泛应用。从异步数据回调到 UI 事件响应,从链式调用到容器数据遍历,其身影无处不在。本文旨在深入探讨 Block 在 ObjC 中的实现,剖析其底层机制,并揭示一些常见的陷阱和最佳实践。
Block 的本质
Block 是一个特殊的函数指针,它封装了函数体和局部变量,实现了函数的一等公民化。这意味着 Block 可以像普通变量一样传递、存储和返回,从而极大地增强了代码的可读性和可维护性。
Block 的语法
returnType (^blockName)(paramType paramName, ...);
其中:
returnType
:Block 返回值类型blockName
:Block 名称paramType
:Block 参数类型paramName
:Block 参数名称
Block 的实现
在底层,Block 是通过一个名为 __block_impl
的结构体实现的。该结构体包含以下成员:
isa
:指向该 Block 的类对象flags
:用于控制 Block 行为的标志reserved
:保留字段invoke
:指向 Block 函数的函数指针descriptor
:指向 Block 符的指针
Block 的使用
异步数据回调
[[AFHTTPSessionManager manager] GET:@"url" parameters:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// 数据请求成功处理
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// 数据请求失败处理
}];
UI 事件回调
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
链式调用
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview).offset(10);
make.left.equalTo(superview).offset(20);
make.right.equalTo(superview).offset(-20);
make.bottom.equalTo(superview).offset(-10);
}];
容器数据遍历回调
NSArray *array = @[@"a", @"b", @"c"];
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%@", obj);
}];
Block 的注意事项
- 循环引用: Block 捕获了外部变量,可能会导致循环引用问题。
- 内存管理: 在 Grand Central Dispatch (GCD) 队列中使用 Block 时,需要特别注意内存管理。
- 避免过早释放: 如果在 Block 仍然被使用时释放了它所捕获的变量,将导致崩溃。
结论
Block 是 ObjC 中强大的工具,能够极大地提高代码的可重用性、可读性和可维护性。通过深入理解 Block 的底层实现和注意事项,开发者可以充分发挥其潜力,编写更加健壮和高效的代码。