правильный способ отправки сообщений переменным (id *) или аргументами (id *) - PullRequest
3 голосов
/ 18 июля 2011

У меня есть метод проверки основных данных, который я написал, который не будет компилироваться.Я могу изменить метод так, чтобы он компилировался ... но тогда я получаю ошибки во время выполнения.Ниже приведены две версии метода (обратите внимание на пропущенный '*' во второй версии).Эта версия компилируется, но выдает ошибку времени выполнения "+ [NSCFNumber doubleValue]: нераспознанный селектор отправлен в класс 0x7fff70a448e8":

- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
    if ( *value == nil ) {
        return YES;
    }
    if ( [*value doubleValue] < 0.0 ) {
        return NO;
    }
    return YES;
}

Эта версия выдает предупреждения и ошибки компилятора (см. Предупреждения и ошибки ниже):

- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
    if ( value == nil ) {
        return YES;
    }
    if ( [value doubleValue] < 0.0 ) {
        return NO;
    }
    return YES;
}

ошибки и предупреждения компилятора:

warning: Semantic Issue: Receiver type 'id *' is not 'id' or interface pointer, consider casting it to 'id'
warning: Semantic Issue: Method '-doubleValue' not found (return type defaults to 'id')
error: Semantic Issue: Invalid operands to binary expression ('id' and 'double')

Я наконец понял, что проблема может заключаться в коде вызова:

- (void)setInitialValue:(NSNumber *)initialValue {
    [self willChangeValueForKey:@"initialValue"];
    [self validateValue:initialValue forKey:@"initialValue" error:nil];
    [self setPrimitiveInitialValue:initialValue];
    [self didChangeValueForKey:@"initialValue"];
}

Я изменил вызывающую сторону для использования '& 'before initialValue и использовал первую версию метода, и все работало.Таким образом, в новом коде вызова одна строка была изменена на следующее:

    [self validateValue:&initialValue forKey:@"initialValue" error:nil];

Но действительно ли необходимо иметь '&' ??setPrimitiveInitialValue не использует '&'.Я чувствую, что мое понимание Objective-C еще недостаточно развито, и все вы, гуру, найдете этот тривиальный вопрос с очень прямым ответом.

Ответы [ 2 ]

5 голосов
/ 18 июля 2011

id сам по себе представляет указатель.Поэтому, когда вы используете id *, вы фактически ссылаетесь на указатель на указатель.Первая часть этого превосходного учебника объясняет эту концепцию.

Скорее всего, это то, что вы ищете:

- (BOOL)validateInitialValue:(id)value error:(NSError **)error {
    if ( value == nil ) {
        return YES;
    }
    if ( [value doubleValue] < 0.0 ) {
        return NO;
    }
    return YES;
}
4 голосов
/ 19 июля 2011

Вы правы, что проблема в коде вызова.id * указывает указатель на значение id.Сама переменная объекта - это id, поэтому вам нужен указатель на эту переменную, который вы получите с помощью &.

. Причина, по которой вы передаете указатель, заключается в том, что если ваша проверка правильностиМетод знает, как изменить значение, чтобы сделать его действительным, он может вернуть YES , а также вернуть действительный объект (путем установки переменной).Так, например, если числа меньше 1 должны быть ограничены до 0, вы можете сделать следующее:

- (BOOL)validateInitialValue:(id *)value error:(NSError **)error {
    if ( *value == nil ) {
        return YES;
    }
    if ( [*value doubleValue] < 0.0 ) {
        return NO;
    }
    if ( [*value doubleValue] > 0.0 && [*value doubleValue] < 1.0 ) {
        *value = [NSNumber numberWithInt:0];
    }
    return YES;
}

setPrimitiveValue: не нужно устанавливать переменные в вызывающем контексте, поэтому просто требуется id.(Очень немногие методы работают как validateValue:forKey:error:. Как правило, они будут делать это таким образом, если захотят вернуть BOOL, чтобы указать, изменили ли они что-то, но им все равно нужен способ вернуть измененное значение.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...