Передача NSNumber * в NSString * Ожидаемый параметр не вызывает предупреждение / ошибку компилятора - PullRequest
2 голосов
/ 25 августа 2011

Есть ли способ это исправить?

Я изменил свою сигнатуру функции, чтобы передать объект NSString вместо объекта NSNumber. За исключением того, что у меня есть несколько экземпляров, которые все еще передают старый объект NSNumber. Трудно отследить, потому что компилятор не отображает никаких ошибок или предупреждений по этому поводу. Я попытался удалить папку DerivedData. Не помогает.

Я также пытался выполнить анализ, который тоже не улавливает эти проблемы.

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

Есть предложения?

- (void) test:(NSString *)par;

вызывающий

NSString *str = (NSString *)[array objectAtIndex:0];

За исключением того, что объект является NSNumber, поэтому технически он преобразует NSNumber в NSString. Отладчик воспринимает его как NSNumber, поэтому не уверен, почему он вообще разрешен.

Ответы [ 3 ]

2 голосов
/ 25 августа 2011

Любой способ это исправить?

не легко.утверждения (как вы упомянули) являются отправной точкой.

Я изменил свою сигнатуру функции, чтобы передать объект NSString вместо объекта NSNumber.

objc неработать так - объекты objc просто передают адреса через свои аргументы / переменные при исполнении.

при преобразовании типов явное преобразование типов не обеспечивается языком;в случае, если это было ваше ожидание.

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

За исключением некоторых случаев, когдапо-прежнему передать старый объект NSNumber.Трудно отследить, потому что компилятор не отображает никаких ошибок или предупреждений по этому поводу.Я попытался удалить папку DerivedData.Не помогает.

вы получаете NSNumbers, потому что это то, что существует в массиве.

Я также пытался выполнить анализ, который также не улавливает эти проблемы.

это очень динамичный язык, и именно так он был спроектирован.

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

также, это обычное дело передавать объекты objc и использовать их динамически (используя respondsToSelector: и isKindOfClass:).

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

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

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

За исключением того, что объект является NSNumber, поэтому технически он преобразует NSNumber в NSString.Отладчик видит его как NSNumber, поэтому не уверен, почему он в первую очередь разрешен.

для переменных objc, отладчик оценивает объект по адресу, чтобы определить его тип, а не использовать тип, объявленныйпеременная.

1 голос
/ 25 августа 2011

Тот факт, что отладчик видит его как правильный (NSNumber) тип, не означает, что компилятор также должен это видеть.Компиляция происходит задолго до отладки, и единственная информация, которую имеет компилятор, - это статический исходный код.Если вы приводите указатель на другой тип, вы фактически указываете компилятору «забыть все, что вы думаете об этом указателе; теперь это ЭТОТ тип».Компилятор не может знать, что на самом деле там будет другой тип во время выполнения.

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

0 голосов
/ 27 августа 2011

Для дальнейшего обсуждения: объекты Objective-C могут рассматриваться как не типизированные.Поскольку среда выполнения является полностью отражающей, и [objTypeA someSelector], и [objTypeB someSelector] создают точно одинаковый скомпилированный код.Это отличается от языков, таких как C ++, где тип объекта должен быть известен, чтобы было понятно, как вызывается конкретный метод.

Другой способ описания этого заключается в том, что Objective-C поддерживает утка набрав .Таким образом, решение вашей проблемы будет следующим:

@interface NSString (stringValue)

- (NSString *)stringValue { return self; }

@end

// ... elsewhere ...

- (void)test:(id)par
{
    NSString *stringValueOfPar = [par stringValue];

    // now proceed with stringValueOfPar as you previously did with par
}

То, что вы там сделали, расширило определение вашего метода тестирования, так что вместо того, чтобы брать определенный тип, он принимает любой тип, который преобразуется встрока при вызове stringValue.NSNumber уже удовлетворяет этому условию, но NSString - нет.Таким образом, вы расширяете NSString.Итак, вы создали неформальный протокол.

Ответ Джастина является более практичным и подходящим для использования, этот - эффективно использовать возможности Objective-C для исправления ошибки, которую вы не должныделать в первую очередь.Я опубликовал этот ответ, чтобы попытаться объяснить, почему подобные вещи не только разрешены в Objective-C, но иногда весьма полезны.

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