2015-04-29 1 views
0

У меня есть словарь. извлечь одно из его значений следующим образом:Objective-c указывает магию. Тип защиты

NSString *magicValue= [filterDict valueForKey:[filterDict allKeys][0]]; 
[SomeClass foo: magicValue]; 

И Foo является:

- (void)foo:(NSString*)magicValue 
{ 
    NSLog("magicValue is string:%@",[magic isKindOfClass:[NSString class]] ? @"YES" : @"NO"); 
    NSLog("magicValue is number:%@",[magic isKindOfClass:[NSNumber class]] ? @"YES" : @"NO"); 
} 

Если значение словаря является число magicValue будет NSNumber. Таким образом, указанный указатель строки будет указывать на NSNumber. Журнал вернет yes для проверки числа.

Я никогда не добавлял защиту таким методам, чтобы проверить, какой класс «magicValue» есть. Я предположил, что когда я определяю метод со строковым параметром, он будет строкой.

Должен ли я начинать учет такого поведения и всегда добавлять проверки, или это вина парня, который присвоил этому значению слова магии таким образом и использовал мой метод. Мне нужен совет по лучшим практикам и как справиться с этим.

Этот вопрос, возможно, уже был дан ответ, но я не знал, как его искать.

ответ

1

Короткий ответ: Нет, не проверяйте это, если нет особых причин.

Длинный ответ:

Вы должны различать два случая:

A. Использование id

У вас есть переменный или обратная юдоль типа id. Это в вашем примере -valueForKey:. Причиной такой типизации является сохранение общего метода. Даже теоретически это возможно, на практике несоответствие типа в такой ситуации встречается очень редко и быстро обнаруживается в развитии. С другой мотивацией я спросил аудиторию (> 200) в публичном разговоре, сколько раз у них была такая типизированная ошибка в производстве. Для всех слушателей все их приложения во всех версиях приложения были 1 (в словах: один!) Случай. Просто забудьте об этом риске. Это тревога разработчиков, использующих статически типизирующие языки (Java, C++, Swift).

B. Неправильное назначение

Если вы не имеете id тип, он по-прежнему можно делать такие трюки. (И иногда вы хотите это сделать. Это сила динамического набора текста.) Есть две подкатегории:

Вы можете сделать это неявно:

NSString *string = [NSNumber numberWithInt:1]; 

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

Можно сделать это явно:

NSString *string = (NSString*)[NSNumber numberWithInt:1]; 

В таком случае, код может сломаться. Но он сделал это явно. Если это неправильно, у разработчика есть криминальная энергия, чтобы сделать это, и вам не нужно защищать его от самого себя.

1

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

Бывают случаи, когда вы имеете дело с наследованием, когда вам нужно определить класс во время выполнения, а не во время компиляции. Это когда isKindOfClass: может быть полезна. Если вы знаете, что значение может быть одним из многих классов, я бы извлек его как id, а затем бросил его в последний момент, например.

id value = [[NSUserDefaults standardUserDefaults] valueForKey:aKey]; 
if ([value isKindOfClass:[MyClass class]]) { 
    // Do one thing 
} 
else { 
    // Do another 
}