Программирование на Objective-C 2.0
Шрифт:
Вернемся к примеру struct date, чтобы задать значение 2010 для компонента year в структуре today. today.year = 2010;
И, наконец, чтобы проверить, что значение month равно 12, можно исполь-зовать оператор if (today, month == 12 ) next_month = 1;
В программе 13.6 реализуется то, что мы обсуждали выше. #import <Foundation/Foundation.h> int main (int arge, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; struct date { int month; int day; int year; }; struct date today; today.month = 9; today.day = 25; today.year = 2009; NSLog (@"Today’s date is %i/%i/%.2i.", today.month, today.day, today.year % 100); [pool drain]; return 0; }
Вывод
В первом операторе внутри main определяется структура с именем date, которая состоит из трех целых компонентов: month, day и year. Во втором операторе объявляется переменная today с типом struct date. Таким образом, в первом опе-раторе просто определяется, как выглядит структура даты для компилятора Objective-C, и не требуется никакого резервирования памяти внутри компьютера. Во втором операторе объявляется переменная типа struct date, и здесь происходит резервирование памяти для хранения трех целых компонентов структурной переменной today.
После присваивания значений соответствующий вызов NSLog выводит зна-чения, содержащиеся в этой структуре. Вычисляется остаток отделения today.year на 100, поэтому функция NSLog выводит для года только две цифры. Символы формата %.2i в обращении к NSLog указывают вывод не менее двух символов, в результате чего для года выводится ведущий нуль.
При вычислении выражений компоненты структуры подчиняются таким же правилам, что и обычные переменные в языке Objective-C. Деление целого ком-понента структуры на другое целое значение выполняется как деление целых, например century = today.year /100+ 1;
Напишем несложную программу, которая принимает на входе текущую дату и выводит завтрашнюю дату (tomorrow). На первый взгляд это кажется совсем простой задачей. Нужно запросить у пользователя ввод текущей даты и затем вычислить завтрашнюю дату с помощью следующего набора операторов. tomorrow.month = today.month; tomorrow.day = today.day + 1; tomorrow.year - today.year;
Конечно, для большинства дат это подходит, но два случая будут реализованы неверно.
Текущая дата приходится на конец месяца.
Текущая дата приходится на конец года (то есть на 3 1 декабря). Чтобы определить, приходится ли текущая дата на конец месяца, нужно задать массив целых значений, соответствующих числу дней каждого месяца.
Поиск в этом массиве даст число дней месяца (см. программу 13.7). // Программа определения завтрашней даты #import <Foundation/Foundation.h> struct date { int month; int day; int year; }; // Функция для вычисления завтрашней даты struct date dateUpdate (struct date today) { struct date tomorrow; int numberOfDays (struct date d); if (today.day != numberOfDays (today)) { tomorrow.day = today.day + 1; tomorrow.month = today.month; tomorrow.year = today.year; } else if (today.month == 12) // end of year { tomorrow.day = 1; tomorrow.month = 1; tomorrow.year = today.year + 1; } else { // конец месяца tomorrow.day = 1; tomorrow.month = today.month + 1; tomorrow.year = today.year; } return (tomorrow); } // Функция для поиска числа дней в месяце int numberOfDays (struct date d) { int answer; BOOL isLeapYear (struct date d); int daysPerMonth[12] = { 31,28, 31, 30, 31, 30, 31, 31,30, 31,30, 31 }; if (isLeapYear (d) == YES && d.month == 2) answer = 29; else answer = daysPerMonth[d. month - 1]; return (answer); } // Функция, определяющая, является ли год високосным BOOL isleapYear (struct date d) { if ((d.year % 4 == 0 && d.year % 100 != 0) || d.year % 400 == 0 ) return YES; else return NO; } int main (int argc, char *argv[]) { NSAutoreleasePool * poo! = [[NSAutoreleasePool alloc] init]; struct date datellpdate (struct date today); struct date thisDay, nextDay; NSLog (@nEnter today’s date (mm dd yyyy):"); scanf ("%i%i%i", SthisDay.month, SthisDay.day, &thisDay.year); nextDay = dateUpdate (thisDay); NSLog (@"Tomorrow’s date is %i/%i/%.2i.",nextDay.month, nextDay .day, nextDay.year % 100); [pool drain]; return 0; }
Вывод
Вывод программы 13.7 (повторный запуск) Enter today’s date (mm dd yyyy): 10 2 2009 Tomorrow’s date is 10/3/09.
Вывод программы 13.7 (повторный запуск) Enter today’s date (mm dd yyyy): 12 31 2010 Tomorrow’s date is 1/1/10.
Хотя мы не работаем в этой программе с классами, здесь был импортирован файл Foundation.!!, поскольку нам нужен тип B00L и определенные имена YES и N0. Они определены в этом файле.
Отметим, что определение структуры данных представлено в первую очередь и вне какой-либо функции. Определения структур данных действуют аналогично переменным. Если структура определена внутри какой-либо функции, только эта функция «знает» о ее существовании, и тогда это локальное определение структуры. Если структура определена вне любой функции, это определение является глобальным. Глобальное определение структуры позволяет объявлять любые последующие переменные (внутри или вне функции) как структуру этого типа. Определения структур, которые используются в нескольких файлах, обычно централизуются водном header-файле и затем импортируются в те файлы, где нужна эта структура.
Внутри процедуры main объявление struct date dateUpdate (struct date today);
указывает компилятору, что функция dateUpdate принимает в качестве аргумента структуру типа date и возвращает структуру такого же типа. Это объявление не обязательно, поскольку компилятор уже «видел» конкретное объявление функции в этом файле, но принято в практике надежного программирования. Если вы в дальнейшем разделите определение этой функции и main на отдельные исходные файлы, объявление будет необходимо.
Как и для обычных переменных (но не для массивов), любые изменения, которые вносятся функцией в значения, содержащиеся в аргументе структуры, не оказывают влияния на исходную структуру. Они влияют только на копию этой структуры, которая создастся при вызове функции.
После ввода даты и ее сохранения в структурной переменной thisDay типа date происходит вызов функции dateUpdate. nextDay = dateUpdate (thisDay);
Здесь происходит вызов функции dateUpdate с передачей этой функции струк-туры даты thisDay.
Внутри функции dateUpdate объявление прототипа int numberOfDays (struct date d);
информирует компилятор Objective-C, что функция numberOfDays возвращает целое значение и принимает один аргумент типа struct date.
Оператор if (today.day != numberOfDays (today))
указывает, что структура today должна передаваться как аргумент функции numberOTOays. Внутри этой функции должно быть соответствующее объявление, информирующее систему, что аргументом должна быть структура, как в следующей строке. int numberOfDays (struct date d)