Программирование на Objective-C 2.0
Шрифт:
Было бы упущением закончить эту главу без описания связей между некоторыми элементами. Поскольку в основе языка Objective-C лежит язык С, имеетсмысл описать некоторые связи между ними. Обратите внимание на эти детали реали-зации, чтобы лучше понять, как все это действует. Мы не будем здесь вдаваться в подробности, а просто приведем четыре факта о связях между Objective-C и С. Факт 1: переменные экземпляра сохраняются в структурах
Когда мы определяем новый класс и его переменные экземпляра, эти переменные на самом деле сохраняются в структуре. На самом деле это структуры, ком-понентами которых являются наши переменные экземпляра. Поэтому насле-дуемые
Одним из наследуемых компонентов этой структуры (он поступает из кор-невого объекта) является защищенный компонент с именем isa, который указывает класс, которому принадлежит объект. Поскольку этот компонент является частью структуры (и гем самым частью объекта), он переносится вместе с объектом. Это позволяет системе runtime всегда идентифицировать класс объекта (даже если он присваивается обобщенной переменной-объекту типа id) по информации его компонента isa.
Чтобы получить непосредственный доступ к компонентам структуры объекта, можно объявить их как @public (см. главу 10). Если сделать это, например, для компонентов numerator и denominator класса Fraction, то можно писать в про-граммах такие выражения, как myFract->numerator
для непосредственного доступа к компоненту numerator объекта myFract класса Fraction. Но мы настоятельно рекомендуем не делать этого. Как говорилось в главе К), это противоречит основам инкапсуляции данных. Факт 2: переменная-объект на самом деле является указателем
Определяя переменную-объект класса Fraction, например, Fraction *myFract;
мы фактически определяем переменную-указатель с именем myFract. Эта пере-менная определяется для указания элемента типа Fraction (это имя нашего класса). При выделении памяти д ля нового экземпляра типа Fraction с помощью строки myFract = [Fraction alloc];
мы выделяем пространство в памяти для хранения нового объекта класса Fraction (то есть пространство для структуры) и затем сохраняем указатель на эту струк-туру, который возвращается в перемен ной-указателе myFract.
Присваивая один объект-переменную другому, как в myFract2 = myFract 1;
мы просто копируем указатели. В результате обе переменные будут указывать на одну структуру, хранящуюся в определенном месте памяти. Поэтому внесение изменений в один из компонентов, который указывается с помощью myFract2, вызывает изменения в той же переменной экземпляра (то есть в компоненте структуры), которую указывает myFractl. Факт 3: методы и функции, а также выражения с сообщениями - это вызовы функций
Методы — это на самом деле функции. При вызове метода мы вызываем функцию, связанную с классом получателя. Аргументы, передаваемые функции, это аргументы получателя (self) и метода. Поэтому все правила, касающиеся передачи аргументов функциям, возвращаемых значений, а также автоматических и статических переменных, одинаковы для функции и метода. Компилятор Objective-C создает уникальное имя для каждой функции в виде комбинации из имени класса и имени метода. Факт 4: тип id - это обобщенный тип указателя
Поскольку обращение к объектам выполняется через указатели, которые являются просто адресами памяти, мы можем легко присваивать им переменные тина id. Поэтому метод, который возвращает тип id, просто возвращает указатель на некоторый объект в памяти. Мы можем затем присвоить это
значение любому объекту-переменной. Поскольку объект при его перемещении сопровождается своим компонентом isa, его класс можно всегда идентифицировать, даже если он хранится в обобщенном объекте-переменной типа id. УпражненияНапишите функцию, которая вычисляет среднее значение 10 элементов массива с плавающей точкой и возвращает результат.
Метод reduce из класса Fraction находит наибольший общий делитель числи-теля и знаменателя (numerator и denominator) для сокращения дроби. Внесите изменения в этот метод, чтобы в нем можно было использовать функцию gcd из программы 13.5. Где следует поместить определение этой функции? Будет ли удобнее сделать эту функцию статической? Какой подход вы считаете более подходящим: использование функции gcd или включение этого кода непосредственно в метод, как мы делали это раньше? Почему?
Алгоритм, известный под названием «Решето Эратосфена», позволяет по-лучать простые числа. Ниже приводится алгоритм для этой процедуры. На-пишите программу, которая реализует этот алгоритм. Сделайте так, чтобы программа находила все простые числа до п = 150. Что вы можете сказать об этом алгоритме по сравнению с алгоритмами в этой книге для расчета простых чисел?
Шаг 1. Определить массив Р с целыми значениями. Присвоить всем элементам Pi значение 0, 2 <= i <= п. Шаг 2. Присвоить i значение 2. Шаг 3. Если i > п, алгоритм завершается. Шаг 4. Earn Pi равно 0, i — простое число. Шаг 5. Для всех положительных целых значений j, удовлетворяющих условию ixj<=n, присвоить Лх) значение 1. Шаг 6. Увеличить i на I и перейти к шагу 3.
Напишите функцию для сложения всех дробей (объектов Fraction), передава-емых ей в массиве, и возвращения результата в виде объекта Fraction.
Напишите определение typedef для структуры struct date с именем Date, чтобы в вашей программе можно было делать, например, следующие объявления. Date todaysDate;
Определение класса Date вместо структуры date больше согласуется с прин-ципами объектно-ориентированного программирования. Определите такой класс с соответствующими методами-установщиками (setter) и получателями (getter). Добавьте метод dateUpdate, чтобы возвращать день по его аргументу. Покажите преимущества определения Date в виде класса, а не в виде струк-туры.
Усматриваете ли вы какие-то недостатки?
В соответствии со следующими определениями char *message = "Программировать на Objective-C интересно"; char me$sage2[] = "Вы сказали это"; int х = 100; определите, является ли допустимым каждый вызов NSLog в следующих на-борах и является ли вывод одинаковым для всех вызовов из этого набора. /*** набор 1 ***/ NSLog {@"Программировать на Objective-C интересно’); NSLog (@"%s',l "Программировать на Objective-C интересно"); NSLog (@"%s\ message); /*** набор 2 ***/ NSLog (@"Вы сказали это"); NSLog (@"%s", message2); NSLog (@"%s", &message2[0j); /*** набор 3 ***/ NSLog (@"сказали это"); NSLog (@"%s", message2 + 4); NSLog (@"%s", &message2[4]);
Напишите программу, которая выводит на терминал все аргументы командной строки (по одному на строку). Обратите внимание на использование кавычек для аргументов, которые содержат пробелы.
Какие из следующих операторов дают на выходе строку "Это проверка"? Объясните результаты. NSLog {@"Это проверка"); NSLog ("Это проверка"); NSLog (@"%s", "Это проверка"); NSLog (@"%s", @"Это проверка"); NSLog ("%s", "Это проверка"); NSLog ("%s", @"Это проверка"}; NSLog (@"%@", @"Это проверка"); NSLog (@"%@", "Это проверка");