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

на главную

Жанры

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

Первая строка определения этого метода: -(Fraction *) add: (Fraction *) f;

Она указывает, что метод add: будет возвращать объект класса Fraction и принимать такой объект в качестве аргумента. Этот аргумент будет складываться с получателем сообщения, которым тоже является объект класса Fraction.

Метод add: выделяет память и инициализирует новый объект типа Fraction с именем result и затем определяет две локальные переменные с именами resultNum и resultDenom. Они будут использоваться для сохранения числителей и знаменателей, получаемых в результате сложения.

После выполнения сложения (как и раньше) и присваивания значений числителей и знаменателей локальным переменным можно задать значение result с помощью следующего выражения. [result setTo: resultNum over: resultDenom];

После сокращения result (на наибольший общий делитель) его значение возвращается отправителю сообщения с помощью оператора return.

Отметим, что занимаемая объектом result память, которая выделена внутри метода add:, возвращается этим методом и не освобождается. Вы не можете освободить ее из метода add:, поскольку она требуется отправителю сообщения.

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

В программе 7.5 выполняется проверка нового метода add:. #import «Fraction.h» int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Fraction *aFraction = [[Fraction alloc] init]; Fraction *bFraction = [[Fraction alloc] init]; Fraction ResultFraction; [aFraction setTo: 1 over: 4]; // присваивание значения 1/4 первой дроби [bFraction setTo: 1 over: 2]; // присваивание значения 1/2 второй дроби [aFraction print]; NSLog (@"+"); [bFraction print]; NSLog resultFraction = [aFraction add: bFraction]; [resultFraction print]; // Непосредственный вывод результата, см. ниже, // вызовет "утечку" памяти! [[aFraction add: bFraction] print]; [aFraction release]; [bFraction release]; [resultFraction release]; [pool drain]; return 0; }

Вывод программы 7.5 1/4 + 1/2 3/4 3/4

Сначала определяются два объекта типа Fraction: aFraction и bFraction, которым присваиваются значения 1/4 и 1/2 соответственно. Здесь также определяется объект Fraction с именем resultFraction (для которого не нужно выполнять выделение памяти и инициализацию). В этой переменной будет сохраняться результат последующих операций сложения.

В следующих строках кода сначала выполняется отправка сообщения add: получателю aFraction с передачей bFraction в качестве аргумента метода. resultFraction = [aFraction add: bFraction]; [resultFraction print];

Результирующий объект типа Fraction, возвращаемый методом, сохраняется в resultFraction и затем выводится путем передачи сообщения print. Отметим, что вы должны аккуратно завершить эту программу, освободив (release) resultFraction, хотя вы не выделяли для нее память (allocate) в main. Код выполнил метод add:, но освободить память должны вы сами. Следующее сообщение кажется очень удобным, но на самом деле здесь возникает проблема. [[aFraction add: bFraction] print];

Поскольку здесь берется объект типа Fraction, возвращаемый методом add:, и ему передается сообщение print, у вас нет никакого способа освободить этот. Мы видим здесь пример утечки памяти (memory leakage). При многократном повторении вложенной передачи сообщения такого рода у вас будет понемногу накапливаться память, которую вы не сможете непосредственным образом освободить.

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

Мы могли бы избежать использования временных переменных resultNum и resultDenom в методе add: с помощью следующего сообщения. [result setTo: numerator * f.denominator + denominator * f.numerator over: denominator * f.denominator;

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

Рассмотрим еще один (последний в этой главе) пример, связанный с дробями. Это суммирование последовательности. ± 1/2 i= I

Оно означает, что нужно сложить значения 1/2i, где i изменяется от 1 до п, то есть сложить 1/2 + 1/4 + 1/8 .... Если сделать значение п достаточно большим, сумма будет приближаться к 1. Мы опробуем несколько значений п, чтобы посмотреть, насколько мы приблизимся к 1.

Программа 7.6 запрашивает ввод значения п и выполняет указанные вычисления. #import Traction.h" int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Fraction *aFraction = [[Fraction alloc] init]; Fraction *sum = [[Fraction alloc] init], *sum2; int i, n, pow2; [sum setTo: 0 over: 1]; // присваивание значения 0 первой дроби NSLog (@"Enter your value for n:"); scant ("%i", &n); pow2 = 2; for (i = 1; i <= n; ++i) { [aFraction setTo: 1 over: pow2]; sum2 = [sum add: aFraction]; [sum release]; // освобождение памяти предыдущей суммы sum = sum2; pow2 *= 2; NSLog (@"After %i iterations, the sum is %g", n, [sum convertToNum]); [aFraction release]; [sum release]; [pool drain]; return 0; }

Вывод программы 7.6 Enter your value for n: (Введите значение n) 5 After 5 iterations, the sum is 0.96875 (По 5 итерациям сумма равна ...) Вывод программы 7.6 (Повторный запуск) Enter your value for n: 10 After 10 iterations, the sum is 0.999023 Вывод программы 7.6 (Повторный запуск) Enter your value for n: 15 After 15 iterations, the sum is 0.999969

Переменной sum типа Fraction присваивается значение 0: числитель (numerator), равный 0, и знаменатель (denominator), равный 1. (А что произойдет, если задать числитель и знаменатель, равные 0?). Затем программа запрашивает у пользователя ввод значения п и считывает его с помощью scant. Затем начинается цикл for для вычисления суммы последовательности. Перед циклом переменной pow2 присваивается значение 2. Эта переменная используется для сохранения значения 2i. На каждом шаге цикла это значение умножается на 2.

Цикл for начинается с 1 и продолжается до значения п. На каждом шаге цикла aFraction присваивается значение 1/pow2, то есть 1/2i. Это значение затем добавляется к сумме (sum) с помощью определенного ранее метода add:. Значение result, возвращаемое из add:, присваивается sum2, а не sum, чтобы избежать проблем утечки памяти. (А что произойдет, если присвоить result непосредственно sum?) Старое значение sum затем освобождается, и для следующего шага цикла sum присваивается новое значение суммы — sum2. Изучите, каким образом здесь происходит освобождение памяти для дробей. Для цикла for, который выполняется сотни или тысячи раз, при неверном освобождении памяти для дробей у вас быстро накопится большой объем неиспользуемой памяти.

По окончании цикла for конечный результат выводится в виде десятичного значения с помощью метода convertToNum. Остается только освободить два объекта: aFraction и конечный объект типа Fraction, сохраненный в sum. После этого завершается выполнение программы.

Результаты вывода показывают, что происходит при запуске программы. При значении 5 сумма последовательности равна 0.96875. При 15 результат очень близок к 1. Расширение определений класса и файл секции interface

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

Герой

Бубела Олег Николаевич
4. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.26
рейтинг книги
Герой

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

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

Кай из рода красных драконов 4

Бэд Кристиан
4. Красная кость
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Кай из рода красных драконов 4

Имя нам Легион. Том 3

Дорничев Дмитрий
3. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 3

Мое ускорение

Иванов Дмитрий
5. Девяностые
Фантастика:
попаданцы
альтернативная история
6.33
рейтинг книги
Мое ускорение

Второгодка. Книга 2. Око за око

Ромов Дмитрий
2. Второгодка
Фантастика:
героическая фантастика
альтернативная история
фэнтези
5.00
рейтинг книги
Второгодка. Книга 2. Око за око

Законник Российской Империи. Том 2

Ткачев Андрей Юрьевич
2. Словом и делом
Фантастика:
городское фэнтези
альтернативная история
аниме
дорама
6.40
рейтинг книги
Законник Российской Империи. Том 2

Золотой ворон

Сакавич Нора
5. Все ради игры
Фантастика:
зарубежная фантастика
5.00
рейтинг книги
Золотой ворон

Мой муж – чудовище! Изгнанная жена дракона

Терин Рем
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Мой муж – чудовище! Изгнанная жена дракона

Второй кощей

Билик Дмитрий Александрович
8. Бедовый
Фантастика:
юмористическое фэнтези
городское фэнтези
мистика
5.00
рейтинг книги
Второй кощей

Бастард Императора

Орлов Андрей Юрьевич
1. Бастард Императора
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Бастард Императора

Дважды одаренный. Том VI

Тарс Элиан
6. Дважды одаренный
Фантастика:
аниме
альтернативная история
фэнтези
фантастика: прочее
5.00
рейтинг книги
Дважды одаренный. Том VI

Деревенщина в Пекине 3

Афанасьев Семен
3. Пекин
Фантастика:
попаданцы
дорама
5.00
рейтинг книги
Деревенщина в Пекине 3

Система Возвышения. (цикл 1-8) - Николай Раздоров

Раздоров Николай
Система Возвышения
Фантастика:
боевая фантастика
4.65
рейтинг книги
Система Возвышения. (цикл 1-8) - Николай Раздоров