
Go语言的defer语句是一种强大的机制,用于确保某个函数调用(或表达式)在当前函数返回之前执行。它常用于资源清理,例如关闭文件、释放锁或取消网络连接。defer语句将函数调用推入一个栈中,当外层函数执行完毕时,这些被延迟的调用会以后进先出(LIFO)的顺序执行。这种模式极大地简化了资源管理,使得清理代码与资源分配代码紧密相邻,提高了代码的可读性和健壮性,尤其是在存在多条返回路径或异常发生时。
Objective-C本身没有内置的defer或类似的延迟执行机制。开发者通常依赖于以下几种方式进行资源清理:
为了在Objective-C中模拟Go语言的defer行为,我们需要一个能够捕获任意代码块,并在函数或特定作用域结束时以LIFO顺序执行这些代码的机制,同时要兼顾异常安全性。
利用Objective-C的Block特性和@try/@finally结构,我们可以构建一个相对通用的defer机制。核心思想是在函数开始时初始化一个可变数组来存储待执行的Block,然后在函数结束的@finally块中,以相反的顺序遍历并执行这些Block。
立即学习“go语言免费学习笔记(深入)”;
以下是实现这一机制的宏定义:
#define SCOPE {id _defered_actions__=[[NSMutableArray alloc]init];@try{
#define END_SCOPE }@finally{for(void(^action)()in[_defered_actions__ reverseObjectEnumerator])action();[_defered_actions__ release];}}
#define DEFER_COPY(_code__) {id _blk__=[^{_code__;}copy];[_defered_actions__ addObject:_blk__];[_blk__ release];}
#define DEFER(_code__) ([_defered_actions__ addObject:(^{_code__;})])宏解释:
示例使用:
#import <Foundation/Foundation.h>
// 宏定义如上所示
#define SCOPE {id _defered_actions__=[[NSMutableArray alloc]init];@try{
#define END_SCOPE }@finally{for(void(^action)()in[_defered_actions__ reverseObjectEnumerator])action();[_defered_actions__ release];}}
#define DEFER_COPY(_code__) {id _blk__=[^{_code__;}copy];[_defered_actions__ addObject:_blk__];[_blk__ release];}
#define DEFER(_code__) ([_defered_actions__ addObject:(^{_code__;})])
@interface XXObject : NSObject {
}
-(int)factorial:(int)x;
@end
@implementation XXObject
-(int)factorial:(int)x { SCOPE // 开始延迟执行作用域
printf("begin foo:%d\n", x);
DEFER( printf("end foo:%d\n", x) ); // 延迟打印函数结束信息
if (x > 0)
return x * [self factorial:x-1];
else if (x == 0)
return 1;
else {
@throw [NSException exceptionWithName:@"NegativeFactorialException"
reason:@"Cannot call factorial on negative numbers"
userInfo:nil];
return 0;
}
END_SCOPE } // 结束延迟执行作用域
-(void)dealloc {
printf("%p has been released.\n", self);
[super dealloc];
}
@end
void do_stuff() { SCOPE // 开始延迟执行作用域
__block XXObject* x = [[XXObject alloc] init]; // 使用__block修饰,以便在Block中修改
DEFER({
printf("releasing %p.\n", x);
[x release]; // 延迟释放对象
});
int i;
for (i = 2; i >= -1; -- i) {
// 使用 DEFER_COPY 来保留局部变量 'i' 和 'fact' 的当前值
int fact = [x factorial:i];
DEFER_COPY( printf("%d! == %d\n", i, fact) ); // 延迟打印阶乘结果
}
END_SCOPE } // 结束延迟执行作用域
int main () {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
@try {
do_stuff();
} @catch(NSException* e) {
// 注意:在64位环境下,如果异常未被捕获,@finally语句可能不会被调用。
NSLog(@"%@", e);
}
[pool drain];
return 0;
}示例输出分析:
begin foo:2 begin foo:1 begin foo:0 end foo:0 // factorial:0 的 defer 打印 end foo:1 // factorial:1 的 defer 打印 end foo:2 // factorial:2 的 defer 打印 begin foo:1 begin foo:0 end foo:0 // factorial:0 的 defer 打印 end foo:1 // factorial:1 的 defer 打印 begin foo:0 end foo:0 // factorial:0 的 defer 打印 begin foo:-1 end foo:-1 // factorial:-1 的 defer 打印 (此处会抛出异常,但 defer 依然执行) 0! == 1 // do_stuff 循环中 i=0 的 defer_copy 打印 1! == 1 // do_stuff 循环中 i=1 的 defer_copy 打印 2! == 2 // do_stuff 循环中 i=2 的 defer_copy 打印 releasing 0x100116500. // do_stuff 中 x 对象的 defer 释放打印 0x100116500 has been released. // x 对象的 dealloc 打印 2011-02-05 23:06:21.192 a.out[51141:903] Cannot call factorial on negative numbers
从输出中可以看出,defer语句的执行顺序是LIFO,并且即使在factorial:方法抛出异常后,其内部的DEFER语句依然能够正常执行,这验证了@finally块的异常安全性。do_stuff中的DEFER_COPY也成功捕获了i和fact的当前值,并在循环结束后按LIFO顺序打印。
变量捕获与DEFER_COPY:
异常安全:
性能考量:
内存管理(MRC vs. ARC):
可读性与维护:
C++集成:
通过巧妙地结合Objective-C的@try/@finally结构和Block特性,我们可以有效地模拟Go语言中defer语句的延迟执行行为。这种模式在需要确保资源在函数或特定作用域结束时(包括异常情况下)被正确清理的场景中非常有用。虽然引入了宏和一些额外的内存开销,但它为Objective-C开发者提供了一种简洁、可靠的资源管理方式,有助于编写更健壮、更易于维护的代码。在实际项目中,应根据具体需求和团队规范,权衡其优缺点并选择最适合的实现方案。
以上就是Objective-C中模拟Go语言的Defer机制:实现延迟执行与资源管理的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号