Вывод типа Objective-C
-
21-09-2019 - |
Вопрос
Хорошо, у меня такое чувство, что вы, ребята, сможете быстро указать, почему я в таком замешательстве по этому поводу, но у меня есть вопрос относительно того, почему следующее НЕ приводит к ошибке компилятора или предупреждению:
NSString * intValue = [ NSString stringWithFormat:@"int = %i", [ [ self.selectedObject valueForKey:name ] integerValue ] ];
selectedObject
является NSObject
, и name
так случилось, что это имя @property
типа int
.
Что меня озадачивает, так это то, почему компилятор вполне готов предположить, что возвращаемый результат [ self.selectedObject valueForKey:name ]
относится к типу NSNumber *
(без приведения его к типу) для того, чтобы связать сообщение с вызовом integerValue
.
Очевидно, что KVC преобразует необъектные типы "number" в NSNumber
, но у компилятора нет возможности узнать это -valueForKey:
вернет NSNumber *
в данном конкретном случае.
Почему это не приводит к предупреждению компилятора в соответствии с "id
может не отвечать на '-integerValue
'"?
Решение
Я надеюсь, что я все понял правильно:Это происходит потому, что id
является “особенным”.Объекты в id
тип может быть отправлен любым сообщением, которое вы хотите, компилятор не выполняет проверку, и все будет проверено во время выполнения.Или, другими словами, id
type - это часть “динамической типизации” Objective-C, тогда как все остальные типы (например NSObject
) являются частью “статической типизации”.
Таким образом, вы можете выбрать, где вы хотите использовать статическую типизацию, а где вы хотите использовать динамическую типизацию.Это совершенно законно - делать что-то подобное:
id str1 = @"Hello";
id str2 = [str1 stringByAppendingString:@", world"];
Но обычно вы вводите строки “плотно”, как NSString
s, потому что вы получаете удобство проверки статического типа во время компиляции и прибегаете к динамической типизации только там, где статическая будет мешать, как в valueForKey
ситуация.
Другие советы
Время прошло, и теперь у нас есть лучший вывод типа благодаря __auto_type
доступно начиная с Xcode 8.Итак, теперь вы можете сделать
#define let __auto_type const
#define var __auto_type
let a = @[@"pew pew"];
var b = 2;
b = a; //compiler warning "Incompatible pointer to integer conversion assigning to 'int' from 'NSArray *__strong const'"
На самом деле, мне это так понравилось, что я сделал это в виде капсулы для удобства.
pod 'SwiftyObjC'