Выполнение кода очистки? - PullRequest
3 голосов
/ 10 января 2010

Вообще говоря, goto - это плохо (мы все знаем почему). Что может быть лучше для простой очистки ошибки (как в примере ниже) без дублирования кода. На мой взгляд, приведенный ниже код в порядке, мне просто любопытно, что будут делать другие:

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]
    int returnCode = 0;

    // ... Other code

    // WRITE: To file
    if([dataStore writeToFile:savePathData atomically:YES] == NO) {
        NSLog(@"writeToFile ... Error");
        returnCode = 1;
        goto cleanUpCode;
    }

    // ... Other code

    // Clean up
    cleanUpCode:
    [archiver release];
    [newPlanet release];
    [pool drain];
    return(returnCode);
}

EDIT_001:

В общих чертах я согласен, что @try, @catch, @finally - это более чем верный путь, но у меня есть две небольшие проблемы.

(1) Все три блока @try, @catch, @finally должны быть все вместе, у вас нет возможности разместить код между @catch и @finally, который вы, возможно, захотите обойти.

(2) Документация Apple для Obj-C 2.0 гласит следующее: «Важно: Исключения являются ресурсоемкими в Objective-C. Вы не должны использовать исключения для общего управления потоком или просто для обозначения ошибок (таких как файл недоступен) ".

высоко ценится

* 1014 Гэри *

Ответы [ 4 ]

5 голосов
/ 10 января 2010

Это распространенная идиома в C-коде, и я не думаю, что с ней что-то не так в отсутствии языка с более полной семантикой создания / уничтожения.общий смысл;это может затруднить выполнение программы.Здесь он очень ограничен по объему, и поток является однонаправленным.Это также полезно в том смысле, что позволяет локализовать код очистки, и это хорошо.

4 голосов
/ 10 января 2010

Ну, во-первых, я попытался бы преобразовать его в еще несколько методов, может быть, тогда код не был бы таким неразборчивым?

Кроме того, вы всегда можете использовать автоматически выпущенные объекты, поэтому вам нужен только [pool drain] в конце. И, вероятно, это можно сделать, используя @try / @finally, так что вы можете просто return 1 вместо returnCode = 1.

например. взгляните на документ Обработка исключений и управление памятью (я знаю, что ваш вопрос не об исключениях, но в основном это одно и то же) - они рекомендуют что-то вроде этого:

 - (void)doSomething {
    NSMutableArray *anArray = nil;
    array = [[NSMutableArray alloc] initWithCapacity:0];
    @try {
       [self doSomethingElse:anArray];
    }
    @finally {
       [anArray release];
    }
}

Лично я бы так и сделал.

0 голосов
/ 10 января 2010

Есть много способов сделать это. Вот пара:

  1. Напишите процедуру, соответствующую вашему основному коду, например, RunApplication. Поместите вызов в ветку "else".

  2. Поместите его в try / catch, выполните обработку ошибок в разделе "catch", в противном случае - обычную обработку.

Код

 e.g. try {
  .. check for error (any function/procedure that checks for an error can throw an exception
 .. do normal processing (still a good idea to factor this out into a procedure, for clarity
 }
 catch  {
     .. handle errors
 }
 finally
 {
     .. do cleanup
 }

Каждый раз, когда вы думаете, что вам нужно перейти, в случае ошибки вы, вероятно, обнаружите, что try / catch и исключение работают лучше.

На языках без try / catch просто используйте рефакторинг.

0 голосов
/ 10 января 2010

Поскольку вы описываете что-то похожее на небольшую программу командной строки, я бы не стал беспокоиться об этом. Потому что, когда ваша программа заканчивается, вся память, выделенная программой, будет возвращена в систему (она перестанет существовать). Но если у вас была более крупная программа, которая выделяет много времени и работает какое-то время, вы, возможно, посмотрите на очистку более правильно, поскольку она может помочь отследить утечки памяти, которые могут повлиять на программу, которая выполняется дольше. В этом случае я бы также предложил использовать несколько макросов.

#define THROW( _name ) goto label_ ## _name
#define CATCH( _name ) label_ ## _name:

    :
    :

    if([dataStore writeToFile:savePathData atomically:YES] == NO) {
        NSLog(@"writeToFile ... Error");
        returnCode = 1;
        THROW( cleanUpCode );
    }

    :
    :

    CATCH( cleanUpCode )

    [archiver release];
    [newPlanet release];
    [pool drain];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...