Реализуете ли вы «отложенный» оператор из Go в Objective-C? - PullRequest
5 голосов
/ 03 февраля 2011

Сегодня я прочитал о выражении defer на языке Go:

A 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 ++?

Я действительно не думаю об использовании этого материала в производстве, я просто интересуюсь различными решениями. Можете ли вы придумать что-нибудь работающее, без явных недостатков? Было бы интересно найти решения как на основе области применения, так и на основе функций.

Ответы [ 2 ]

1 голос
/ 05 февраля 2011

Если вы можете использовать C ++, проверьте библиотеку Boost's Scope Exit .


Если вы не возражаете против ввода 2 дополнительных слов в начале и конце функции, вы можете использовать блок @ finally .

#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
1 голос
/ 03 февраля 2011

Прочтите сообщение Майка Эша о генераторе в Objective-C .

...