Как тип «id» понимает получатель метода без приведения? - PullRequest
0 голосов
/ 05 октября 2018

После слияния master с моей рабочей веткой я получил ошибку компилятора в строке, которая не была изменена.Ошибка выглядит следующим образом:

id test;
[test count];

Несколько методов с именем 'count' найдено с ошибочным результатом.

Сначала это выглядит ясно, потому что компилятор не знает, какой конкретныйвведите переменную «test».Но я не понимаю, почему он работал раньше.

  1. Если я создаю новый файл, эта строка работает, предполагая, что это метод NSArray.Почему компилятор не показывает ошибку в этом случае?

  2. При отображении сообщения об ошибке показаны несколько возможных получателей метода подсчета.(NSArray, NSDictionary, NSSet) Поиск всех классов, которые могут получить это сообщение и показать ошибку, если их несколько?

  3. Я заметил, что ошибка возникает при импорте "-Swift.h" файл.Как это зависит?

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Objective-C не нужно знать тип получателя.Во время выполнения все объекты просто id, и все отправляется динамически.Таким образом, любое сообщение может быть отправлено любому объекту, независимо от его типа.(Во время выполнения объекты могут сами решать, что делать с сообщениями, которые они не понимают. Наиболее распространенная вещь, которую нужно сделать, это вызвать исключение и аварийный отказ, но есть много видов объектов, которые могут обрабатывать произвольные сообщения, которые не '• сопоставить непосредственно вызовам методов.)

Однако есть несколько технических деталей, которые усложняют это.

ABI (двоичный интерфейс приложения) определяет различные механизмы для возврата определенных примитивных типов.Пока значение является «целочисленным размером в слово», тогда это не имеет значения (это включает в себя такие вещи, как NSInteger и все указатели, что означает расширение всех объектов).Но на некоторых процессорах числа с плавающей точкой возвращаются в регистры, отличные от целых чисел, и структуры (например, CGRect) могут быть возвращены различными способами в зависимости от их размера.Чтобы написать необходимый язык ассемблера, компилятор должен знать, каким будет возвращаемое значение.

В ARC добавлены дополнительные складки, которые требуют, чтобы компилятор знал больше о типе параметров (в частности,являются ли они объектами или примитивами), и есть ли какие-либо атрибуты управления памятью, которые необходимо учитывать.

Компилятору на самом деле все равно, что такое "настоящий" тип test, покаон может выяснить типы и атрибуты -count.Поэтому, имея дело со значением id, он просматривает все известные селекторы, которые он видит (то есть каждый, определенный во включенном заголовке или текущем .m).Хорошо, если их много в разных классах, если они все согласны.Но если он вообще не может найти селектор или некоторые интерфейсы не согласны, он не может скомпилировать строку кода.

Как отмечает lobstah, у вас, вероятно, есть тип где-то в вашем Swiftкод, который имеет метод @objc с именем count() или свойство @objc с именем count, которое возвращает что-то отличное от Int (которое сопоставляется с NSInteger и соответствует обычной подписи -count).Вам нужно будет исправить этот метод, или вам нужно будет скрыть его от ObjC (например, добавив @nonobjc).

Или намного лучше: избавьтесь от id и используйтеего актуальный тип.id обычно плохая идея в Какао, и особенно плохая, если вы вызываете методы для него, так как компилятор не может проверить, будет ли объект реагировать, и вы можете потерпеть крах.

0 голосов
/ 05 октября 2018

Компилятор не приводит или не проверяет ваш тип id.Он просто предоставляет вам все возможные селекторы.Вы сказали, что эта проблема связана с импортом файла "-Swift.h".В этом случае проверьте ваш код Swift, возможно, у вас есть функция count, видимая для Objective C, которая возвращает что-то отличное от Int.

Также вы можете проверить проблему в Issue navigator, выбрать ее ипокажет все count вызовы, видимые в Objective C. Отметьте их все, большинство из них возвратит NSUInteger, но должен быть один, который возвращает что-то еще, например:

SWIFT_CLASS("_TtC3dev19YourClass")
@interface YourClass : NSObject
- (int32_t)count SWIFT_WARN_UNUSED_RESULT;
@end

...