6

今天我读到defer了 Go 语言中的语句:

defer语句将函数调用推送到列表中。保存的调用列表在周围函数返回后执行。Defer 通常用于简化执行各种清理操作的函数。

我认为在 Objective-C 中实现这样的东西会很有趣。你知道怎么做吗?我想到了调度终结器、自动释放对象和 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"));
    …
}

自动释放对象似乎是唯一至少会持续到函数结束的解决方案,因为其他解决方案会在当前范围结束时触发。另一方面,他们可以在记忆中停留更长时间,这将是自找麻烦。

调度终结器是我的第一个想法,因为块存在于堆栈中,因此当堆栈展开时我可以轻松地执行某些操作。但是在查看文档之后,看起来我不能将一个简单的“析构函数”函数附加到一个块上,可以吗?

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

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

4

2 回答 2

2

If you could use C++, check Boost's Scope Exit library.


If you don't mind having to type 2 extra words in the beginning and the end of the function, you could use the @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__;})])

Example use:

@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;
}

Which should print:

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
于 2011-02-05T15:20:57.750 回答
1

阅读 Mike Ash在 Objective-C 中关于生成器的帖子。

于 2011-02-03T08:57:02.337 回答