objective-c - 在 Objective-C 中实现 Go 中的 ‘defer’ 语句?

标签 objective-c go deferred-execution

今天看了Go语言的defer语句:

A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.

我认为在 Objective-C 中实现这样的东西会很有趣。你知道怎么做吗?我想到了分派(dispatch)终结器、自动释放对象和 C++ 析构函数。

自动释放的对象:

@interface Defer : NSObject {}
+ (id) withCode: (dispatch_block_t) block;
@end

@implementation Defer
- (void) dealloc {
    block();
    [super dealloc];
}
@end

#define defer(__x) [Defer withCode:^{__x}]

- (void) function
{
    defer(NSLog(@"Done"));
    …
}

自动释放对象似乎是唯一至少会持续到函数结束的解决方案,因为其他解决方案会在当前作用域结束时触发。另一方面,它们可以在内存中停留更长时间,这会带来麻烦。

Dispatch 终结器是我的第一个想法,因为 block 存在于堆栈中,因此我可以轻松地在堆栈展开时执行某些操作。但是在浏览了文档之后,我似乎无法将一个简单的“析构函数”函数附加到 block 上,对吗?

C++ 析构函数大致相同,我会创建一个基于堆栈的对象,其中包含一个在析构函数运行时要执行的 block 。这会带来将普通 .m 文件转换为 Objective-C++ 的丑陋缺点吗?

我并没有真正考虑在生产中使用这些东西,我只是对各种解决方案感兴趣。你能想出一些有用的东西,没有明显的缺点吗?基于范围和基于功能的解决方案都会很有趣。

最佳答案

如果您可以使用 C++,请查看 Boost 的 Scope Exit图书馆。


如果您不介意在函数的开头和结尾输入 2 个额外的单词,您可以使用 @finally block 。

#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];
    DEFER({
        printf("releasing %p.\n", x);
        [x release];
    });


    int i;
    for (i = 2; i >= -1; -- i) {
        // use DEFER_COPY to retain the local variable 'i' and '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) {
        // note that the @finally statements might not be called in 64-bit if we
        // left the exception uncaught.
        NSLog(@"%@", e);
    }
    [pool drain];
    return 0;
}

应该打印:

begin foo:2
begin foo:1
begin foo:0
end foo:0
end foo:1
end foo:2
begin foo:1
begin foo:0
end foo:0
end foo:1
begin foo:0
end foo:0
begin foo:-1
end foo:-1
0! == 1
1! == 1
2! == 2
releasing 0x100116500.
0x100116500 has been released.
2011-02-05 23:06:21.192 a.out[51141:903] Cannot call factorial on negative numbers

关于objective-c - 在 Objective-C 中实现 Go 中的 ‘defer’ 语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4883760/

相关文章:

javascript - Underscorejs 'defer'(或 setTimeout 1)无法持续工作

javascript - <script defer ="defer"> 到底是如何工作的?

java - iOS 中的事件总线等效项

ios - 使用 NSString 作为键和值创建 JSON 格式

ios - 改变动画的位置?

amazon-web-services - golang附加到二维 slice

go - 在哪里存储测试(项目结构-最佳实践)?

objective-c - iOS 应用程序上的红条

go - Go-Gorm有一个始终为空的子表

c# - 延期执行会不会先调用Dispose导致失败?