Чтение онлайн

на главную

Жанры

Программирование на Objective-C 2.0
Шрифт:

Вывод программы 8.6 х = 200 Сообщение [b initVar];

вызывает использование метода initVar, определенного в ClassB, а не одноименного метода из ClassA, как в предыдущем примере (рис. 8.9).

Рис. 8.9. Замещение метода initVar Какой из методов выбирается?

Мы уже описывали, каким образом система выполняет поиск в иерархии, чтобы найти метод для применения к объекту. Если у вас есть методы с одинаковым именем в различных классах, то нужный метод выбирается в соответствии с классом получателя сообщения. В программе 8.7 используются такие же определения для классов ClassA и ClassB, как выше. #import <Foundation/Foundation.h> // Здесь нужно вставить определения для классов ClassA и ClassB int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; ClassA *a = [[ClassA alloc] init]; ClassB *b = [[ClassB alloc] init]; [a initVar]; // использование метода из ClassA [a printVar]; // раскрытие значения x; [b initVar]; // использование замещающего метода из ClassB [b printVar]; // раскрытие значения x; [a release]; [b release]; [pool drain]; return 0; }

Для этой программы вы получите следующее предупреждающее сообщение: warning: 'ClassA' may not respond to ’-printVar’ (предупреждение: ’ClassA’, возможно, не отвечает '-printVar'

Что произошло? Рассмотрим объявление класса ClassA: // Объявление и определение класса ClassA @interface ClassA: NSObject { int x; -(void) initVar; @end

Обратите внимание, что не объявлен никакой метод printVar. Этот метод объявлен и определен в ClassB. И хотя объекты ClassB и их потомки могут использовать этот метод путем наследования, объекты класса ClassA не могут это сделать, поскольку данный метод определен ниже в цепочке иерархии.

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

Вернемся к примеру и добавим метод printVar в класс ClassA, чтобы вывести значение его переменных экземпляра. // Объявление и определение класса ClassA @interface ClassA: NSObject { int x; -(void) initVar; -(void) printVar; @end @implementation ClassA -(void) initVar { x = 100; } -(void) printVar { NSLog (@"x = %i", x); } @end

Объявление и определение класса ClassB остается без изменений. Запустим компиляцию и выполнение программы.

Вывод программы 8.7 х= 100 х = 200

а и b определены как объекты классов ClassA и ClassB соответственно. После выделения памяти и инициализации передается сообщение для объекта а, у которого запрашивается применение метода initVar. Этот метод определен в определении класса ClassA, поэтому выбирается именно он. Он присваивает значение 100 переменной экземпляра х и выполняет возврат. Затем вызывается метод printVar, только что добавленный в класс ClassA, чтобы вывести значение х. Выделение памяти и инициализация для объекта b класса ClassB выполняется так же как и для объекта класса ClassA, его переменной экземпляра присваивается значение 200 и выводится ее значение.

Постарайтесь разобраться, как для переменных а и b происходит выбор метода, исходя из класса, которому они принадлежат. Это одна из базовых концепций объектно-ориентированного программирования в Objective-C.

В качестве упражнения попробуйте удалить метод printVar из класса ClassB. Получится ли это? Почему? Замещение метода dealloc и ключевое слово super

Теперь, когда вы знаете, как замещать методы, вернемся к программе 8.5В, чтобы изучить более подходящий способ освобождения памяти, выделенной для origin. Метод setOrigin: выделяет память для своего собственного объекта origin класса XYPoint, и вы обязаны освободить эту память. В программе 8.6 освобождение памяти выполнял оператор: [[myRect origin] release];

Вам не нужно заботиться об освобождении всех отдельных членов класса; вы можете заместить метод dealloc (наследуемый из NSObject) и освободить там память origin.

Примечание. Мы будем замещать метод dealloc, а не метод release. Метод release иногда освобождает память, используемую объектом, а иногда нет. Он освобождает память, используемую объектом, только если никто другой не обращается к этому объекту, и делает это, вызывая метод объекта dealloc, который фактически освобождает память.

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

Для этого существует специальное ключевое слово super, которое обозначает родительский класс получателя сообщения. Для выполнения замещаемого метода нужно передать super сообщение. Выражение с сообщением [super release];

при использовании внутри метода вызывает метод release, который определен (или унаследован) в родительском классе. Этот метод вызывается в получателе сообщения, то есть в себе самом (self).

Таким образом, замещение метода dealloc для класса Rectangle выполняется следующим образом. Сначала освобождается память, занятая origin, а затем вызывается метод dealloc из родительского класса. Тем самым освобождается память, занятая самим объектом Rectangle. Ниже приводится этот метод. -(void) dealloc { if (origin) [origin release]; [super dealloc]; }

Определенный здесь метод dealloc не возвращает никакого значения. Внутри метода сначала dealloc выполняется проверка, что origin имеет ненулевое значение. Начало прямоугольника (origin), возможно, не было задано. В этом случае он имеет по умолчанию нулевое значение. Затем вызывается метод dealloc из родительского класса, который был бы унаследован классом Rectangle, если бы не был замещен.

Метод dealloc можно написать проще: -(void) dealloc { [origin release]; [super dealloc]; }

поскольку вы можете без проблем передать сообщение nil-объекту. Кроме того, к origin применяется release, а не dealloc. В любом случае, если никто другой не использует origin, release вызовет метод dealloc для origin, чтобы освободить его пространство. Используя этот метод, вы должны освобождать только те объекты-прямоугольники, для которых выделили память, не заботясь об объектах XYPoint, которые они содержат. Двух сообщений, показанных в программе 8.5, теперь достаточно, чтобы освободить память для всех объектов, в том числе объекта XYPoint, создаваемого с помощью setOrigin:. [myRect release]; [myPoint release];

Правда, остается одна проблема. Если задать для начала прямоугольника (origin) одного объекта Rectangle другие значения во время выполнения программы, то вы должны освободить память, занятую прежним началом прямоугольника, прежде чем выделить и назначить новую. Рассмотрим следующую последовательность строк: myRect.origin = startPoint; myRect.origin = endPoint; [startPoint release]; [endPoint release]; [myRect release];

Копия объекта startPoint класса XYPoint, сохраненная в элементе origin myRect, не будет освобождена, поскольку она перезаписывается вторым значением для origin (endPoint). Эта копия origin будет освобождена правильно, когда будет освобождаться сам объект прямоугольника, если применяется новый метод освобождения памяти.

Поделиться:
Популярные книги

Старый, но крепкий 4

Крынов Макс
4. Культивация без насилия
Фантастика:
уся
фэнтези
5.00
рейтинг книги
Старый, но крепкий 4

Точка Бифуркации X

Смит Дейлор
10. ТБ
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Точка Бифуркации X

Живое проклятье

Алмазов Игорь
3. Жизнь Лекаря с нуля
Фантастика:
попаданцы
альтернативная история
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Живое проклятье

Древесный маг Орловского княжества 6

Павлов Игорь Васильевич
6. Орловское княжество
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Древесный маг Орловского княжества 6

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

Газлайтер. Том 9

Володин Григорий
9. История Телепата
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Газлайтер. Том 9

Черный Маг Императора 14

Герда Александр
14. Черный маг императора
Фантастика:
аниме
сказочная фантастика
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Черный Маг Императора 14

Виконт. Книга 4. Колонист

Юллем Евгений
Псевдоним `Испанец`
Фантастика:
фэнтези
попаданцы
аниме
7.50
рейтинг книги
Виконт. Книга 4. Колонист

Точка Бифуркации III

Смит Дейлор
3. ТБ
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Точка Бифуркации III

Вторая жизнь майора. Цикл

Сухинин Владимир Александрович
Вторая жизнь майора
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Вторая жизнь майора. Цикл

Вечный. Книга V

Рокотов Алексей
5. Вечный
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Вечный. Книга V

Печать пожирателя 2

Соломенный Илья
2. Пожиратель
Фантастика:
городское фэнтези
попаданцы
аниме
сказочная фантастика
5.00
рейтинг книги
Печать пожирателя 2

Проданная Истинная. Месть по-драконьи

Белова Екатерина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Проданная Истинная. Месть по-драконьи

Неудержимый. Книга XXVIII

Боярский Андрей
28. Неудержимый
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Неудержимый. Книга XXVIII