Понимание предметной области Objective-C - PullRequest
5 голосов
/ 20 июля 2011

Ниже приведен фрагмент из реализации View Controller:

- (void)myOtherAwesomeMethod
{
    [self myAwesomeMethod]; // Compile ERROR here: Receiver type for instance message does not declare a method with selector
}

- (void)myAwesomeMethod
{
    NSLog(@"%@", @"Calling my awesome method...");
}

- (void)viewDidLoad
{
    [self myAwesomeMethod];

    [self myOtherAwesomeMethod];
}

У меня нет метода myAwesomeMethod, объявленного в моем заголовочном файле, но почему я могу вызвать myAwesomeMethod в * 1006?*, но не в myOtherAwesomeMethod?

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

Ответы [ 2 ]

11 голосов
/ 20 июля 2011

В C правило: вы должны объявить его перед использованием.

Файлы компилируются сверху вниз. Итак, вот что происходит в вашем коде:

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

    Ваша таблица символов содержит: еще ничего

  2. Компилятор читает определение метода для myAwesomeMethod. Вы еще не объявили об этом, поэтому он добавляется в таблицу символов. Тело метода содержит вызов NSLog, который был давно объявлен в заголовке, предоставленном Apple.

    Ваша таблица символов содержит: myAwesomeMethod

  3. Компилятор читает определение метода для viewDidLoad; это было фактически объявлено в заголовочном файле суперкласса. Тело метода содержит вызов myAwesomeMethod, который был найден! Он также содержит звонок на myOtherAwesomeMethod. Никогда не слышал об этом!

    Теперь, это не ошибка, потому что он все еще может генерировать код для вызова. Он может определять типы аргументов по тому, как вы их используете (в данном случае без аргументов). Тем не менее, он не может быть уверен в типе возвращаемого значения (то, что вы не используете возвращаемое значение, не означает, что его не было). Поэтому он исходит из предположения, что вызов возвращает id и выдает предупреждение.

    Ваша таблица символов содержит: myAwesomeMethod

  4. Наконец, компилятор читает определение метода для myOtherAwesomeMethod. Он добавляется в таблицу символов. Он компилирует тело, которое содержит вызов myAwesomeMethod, который находится в таблице. Все хорошо, что хорошо кончается.

    В конце файла ваша таблица символов содержит: myAwesomeMethod, myOtherAwesomeMethod

Если вы пришли из такого языка, как Java, это может показаться глупым, но это потому, что Java работает иначе, чем C. В Java исходный код компилируется и связывается за один шаг; Вы не можете скомпилировать класс, который ссылается на другой класс, не имея ни исходного кода, ни файлов классов. Это может быть хлопотно, но, с другой стороны, вам никогда не понадобятся объявления, кроме определений.

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

В Objective-C компоновщик на самом деле не знает / не заботится о сообщениях Objective-C, потому что нет способа узнать во время компиляции / во время компоновки, может ли объект ответить на сообщение. Таким образом, он перекладывает ответственность на среду выполнения, которая выдает исключение, если вы заходите далеко без определения метода.

0 голосов
/ 20 июля 2011

Признаюсь, я не уверен, почему это работает в viewDidLoad.

Обратите внимание, что в сообщении об ошибке указано "не объявлен" метод. Это намек на то, что он ищет объявление (обычно в заголовке) .. т.е. прототип функции.

Однако нет ничего, что говорит о том, что объявление должно быть в заголовке. Вы можете поместить его в начало файла реализации, если не собираетесь вызывать этот метод извне файла.

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