В Objective-C я пытаюсь инкапсулировать несколько вызовов с ошибками и «вернуть» наиболее полезную ошибку - PullRequest
2 голосов
/ 26 мая 2010

Я помещаю «return» в кавычки, потому что я не хочу буквально возвращать его. Я хочу сделать это подобно тому, как вы передаете указатель на указатель для [NSString stringWithContentsOfFile:usedEncoding:error:].

Я хотел бы, чтобы parseFiles:error возвратил ноль и имел ссылку на ошибку, которая была передана, содержит первую или вторую ошибку, в зависимости от того, какая из них была неудачной. Похоже, какао способ сделать это?

РЕДАКТИРОВАТЬ: Извините, я должен был быть более ясным о том, где у меня была проблема. Если первый путь фиктивный, он функционирует так, как я хочу. (Я получаю экземпляр ошибки снаружи, и он печатает.) Если первый путь допустим, как следует из приведенной ниже строки-заполнителя, я получаю EXC_BAD_ACCESS.

Но теперь я исправил это. Мне нужно сослаться на него как *error внутри метода parseFiles:error: и использовать == nil при проверке, не удалось ли это. Я думал, что мог бы просто if (error) ...

РЕДАКТИРОВАТЬ 2 Хорошо, это не работает. Я получаю EXC_BAD_ACCESS. Я не уверен, что я делаю не так с условиями, которые проверяют ошибки.

@implementation PassingError

- (id)init {
    self = [super init];

    NSError *error;
    [self parseFiles:@"/untitled.py" error:&error];

    if (error != nil) {
        NSLog(@"I failed because: %@", error);
    }
    return self;
}

// Wraps with reading errors.
- (NSString *)parseFiles:(NSString *)path error:(NSError **)error {

    NSStringEncoding enc1;
    NSString *contents1 = [NSString stringWithContentsOfFile:path
                                               usedEncoding:&enc1 error:*&error];

    // there was a read error

    // I need an asterisk here...
    if (*error != nil) {
        // ...and also one here
        NSLog(@"FIRST ERROR: %@", *error);
        return nil;
    }


    // here is where you'd do something that might cause another error,
    // I'll just try and read a second file for simplicity
    NSStringEncoding enc2;
    NSString *contents2 = [NSString stringWithContentsOfFile:@"/untitled.py"
                                               usedEncoding:&enc2 error:*&error];

    // there was a SECOND error
    if (*error != nil) {
        NSLog(@"SECOND ERROR: %@", *error);
        return nil;
    }


    // return both or whatever
    return [NSArray arrayWithObjects:contents1, contents2, nil];
}

@end

1 Ответ

3 голосов
/ 26 мая 2010

Передача указателей в Objective-C может привести к путанице. Я помню, как мне было трудно понять, что нужно сделать. Если у вас есть такой метод:

- (BOOL) saveValuesAndReturnError:(NSError **) error
{
    BOOL success = [self doSomethingImportant];

    if (!success && error)
    {
        // Unsuccessful and error is a valid ptr-to-ptr-to-NSError.

        // Basically, someone has given us the address of a (NSError *).
        // We can modify what that pointer points to here.
        *error = [NSError errorWithDomain:@"myDomain" code:100 userInfo:nil];
    }

    return success;
}

Это должно быть вызвано так:

// If the caller doesn't care that it failed:
[someObject saveValuesAndReturnError:NULL];



// Or, if the caller wants to get error information on failure
NSError *anError = nil;
BOOL success;

// pass address of our (NSError *)
success = [someObject saveValuesAndReturnError:&anError];
if (!success)
{
    // anError now points to an NSError object, despite being initialised to nil,
    // because we passed the address of our NSError ptr, the method was able to 
    // change where `anError` points to.
    NSLog (@"An error occurred while saving values: %@", anError);
}

Возможно, очень уместным прочтением в этом случае является сообщение в блоге CIMGF , охватывающее именно эту тему.

Однако ...

Я помню, как читал некоторое время назад, что методы, которые возвращают ошибки через аргументы методов, такие как stringWithContentsOfFile:usedEncoding:error:, не дают никаких гарантий не изменять аргумент ошибки для успеха. Другими словами, вы не можете полагаться на значение параметра ошибки, если метод завершился успешно. В вашем конкретном случае может быть лучше сделать:


- (NSString *)parseFiles:(NSString *)path error:(NSError **)error {

    NSStringEncoding enc1, enc2;
    NSError *innerError;
    NSString *contents1 = [NSString stringWithContentsOfFile:path
                                                usedEncoding:&enc1
                                                       error:&innerError];

    if (contents1 == nil)
    {
        if (error) *error = innerError;
        return nil;
    }

    NSString *contents2 = [NSString stringWithContentsOfFile:@"/untitled.py"
                                                usedEncoding:&enc2
                                                       error:&innerError];

    if (contents2 == nil)
    {
        if (error) *error = innerError;
        return nil;
    }

    // do whatever with contents1 and contents2
}

...