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

на главную - закладки

Жанры

Программирование на 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 будет освобождена правильно, когда будет освобождаться сам объект прямоугольника, если применяется новый метод освобождения памяти.

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

Лекарь Империи 10

Карелин Сергей Витальевич
10. Лекарь Империи
Фантастика:
городское фэнтези
боевая фантастика
аниме
попаданцы
5.00
рейтинг книги
Лекарь Империи 10

Кодекс Крови. Книга ХVIII

Борзых М.
18. РОС: Кодекс Крови
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Кодекс Крови. Книга ХVIII

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

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

Маленькая женщина Большого

Зайцева Мария
5. Наша
Любовные романы:
эро литература
современные любовные романы
5.00
рейтинг книги
Маленькая женщина Большого

Ты - наша

Зайцева Мария
1. Наша
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Ты - наша

Кодекс Охотника. Книга XXXIII

Винокуров Юрий
33. Кодекс Охотника
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Кодекс Охотника. Книга XXXIII

Законы Рода. Том 9

Мельник Андрей
9. Граф Берестьев
Фантастика:
городское фэнтези
попаданцы
аниме
дорама
фэнтези
фантастика: прочее
5.00
рейтинг книги
Законы Рода. Том 9

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

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

Последний Паладин. Том 9

Саваровский Роман
9. Путь Паладина
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Последний Паладин. Том 9

Черный маг императора 3

Герда Александр
3. Черный маг императора
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора 3

Адвокат Империи 15

Карелин Сергей Витальевич
15. Адвокат империи
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Адвокат Империи 15

Чужая семья генерала драконов

Лунёва Мария
6. Генералы драконов
Фантастика:
фэнтези
5.00
рейтинг книги
Чужая семья генерала драконов

Третий. Том 6

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
фантастика: прочее
попаданцы
5.00
рейтинг книги
Третий. Том 6

Слезы Эйдена 1

Владимиров Денис
11. Глэрд
Фантастика:
боевая фантастика
фэнтези
попаданцы
5.00
рейтинг книги
Слезы Эйдена 1