Текст книги "Программирование на Objective-C 2.0"
Автор книги: Стивен Кочан
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 31 (всего у книги 32 страниц)
Если метод не принимает никаких аргументов,то этот формат используется для вызова метола имя из класса, указанного получателем.
Если получатель имеет тип id, то компилятор ищет среди объявленных классов определение или наследуемое определение указанного метода. Если не найдено такого определения, компилятор выводит предупреждение, что получатель не ответит на указанное сообщение. Кроме того, предполагается, что метод возвращает значение типа id и преобразует любые аргументы типа float в тип double, а также выполняет целочисленное расширение для любых целых аргументов, как описано выше в разделе «Преобразование базовых типов данных». Другие аргументы метода передаются без преобразования.
Если получатель является объе кто м – классом (который можно создать, просто указав имя класса), то вызывается указанный метод класса. В противном случае получатель является экземпляром класса, и тогда вызывается соответствующий метод экземпляра.
Если получатель является переменной или выражением со статическим конт-ролем типа, то компилятор ищетметод в определении класса (или среди любых наследуемых методов) и преобразует любые аргументы (когда это возможно), чтобы он и соответствовали ожидаемым аргументам данного метода. Например, если метод должен получать значение с плавающей точкой и ему передано значение целого тина, соответствующий аргумент автоматически преобразуется при вызове этого метода.
Если получатель является указателем на null-объект, то есть nil, ему тоже можно передавать сообщения. Если метод, связанный с сообщением, возвращает объект, то выражение с этим сообщением дает значение nil. Если метод не возвращает какого-либо объекта, то значение этого выражения не определено.
Если один и тот же метод определен более чем в одном классе (путем явного определения или врезультате наследования), компилятор проверяет среди этих классов соответствие типам аргументов и возвращаемою значения.
Все аргументы передаются методу по значению, поэтому их значения не могут быть изменены методом. Если методу передается указатель, то метод может изменять значения, на которые ссылается этот указатель, но метод все же не может изменять значение самого указателя. Формат 3 получатель.свойство
Это вызов getter-метода, то есть метода-получателя (по умолчанию свойство) для получателя, если выражение не используется как lvalue-выражение (см. Формат 4). Имя getter-метода можно изменять с помощью директивы @property, и тогда это будет вызываемый метод.
Если используется имя getter-метода по умолчанию, то приведенное выше выражение эквивалентно следующему. [получатель свойство] Формат 4 получатель.свойство = выражение
Это вызов setter-метода (метода-установщика), связанного со свойством свой-ство, и в качестве его аргумента передается значение выражения. По умолчанию вызывается setter-метод ^Свойство:, если для этого свойства не было назначено имя другого setter-метода с использованием предшествующей директивы @property.
Если используется имя setter-метода по умолчанию, то приведенное выше выражение эквивалентно следующему. [получатель set Свойство: выражение] Программные операторы
Программным оператором (program statement) является любое допустимое вы-ражение (обычно присваивание или вызов функции), которое закапчивается точкой с запятой, или это один из специальных операторов, описанных ниже. Перед любым оператором можно ставить необязательную метку; метка состоит из идентификатора, после которого ставится символ «двоеточие» (см. также оператор goto). Составные операторы
Программные операторы, содержащиеся в фигурных скобках, называются со-ставным оператором, или блоком, и могут находиться в любом месте программы, где допустим хоть один оператор. Блок может содержать свой собственный набор объявлений переменных, которые могут замещать одноименные переменные, определенные вне этого блока. Областью действия таких локальных переменных является блок, в котором они определены. Оператор break
Общий формат break;
Выполнение оператора break внутри области действия оператора for, while, do или switch вызывает прекращение работы этого оператора. Выполнение про-должается с оператора, непосредственно следующего после цикла или пере– ключалеля (switch). Оператор continue
Общий формат continue;
Выполнение оператора continue внутри цикла вызывает пропуск операторов, которые следуют в этом цикле непосредственно после continue. В проти виом слу-чае выполнение цикла продолжается обычным образом. Оператор do
Общий формат do программный Оператор while (выражение);
Если выражение имеет ненулевое значение, то выполняется программныйОпера– юр. Отметим, что поскольку выражение вычисляется каждый раз после того, как выполнен программныйОпераюр, здесь гарантируется, что программныйОператор будет выполнен хотя бы один раз. Оператор for Формат 1 for (выражение_ 1; выражение_2; выражение_3) програтныйОператор
Выражение_1 вычисляется один раз, когда начинается выполнение цикла. Затем вычисляется выражение_2. Если это выражение имеет ненулевое значение, то выполняется программныйОператор и затем вычисляется выражение_3. Это про-исходит, пока выражение_2 имеет ненулевое значение. Поскольку выражение_2вычисляется каждый раз перед тем, как выполняется программныйОператор, этот оператор может быть никогда не выполнен, если выражение_2 имеет значение 0 при первом входе в цикл.
Для выражения_ 1 можно объявить переменные, локальные для данного цикла for. Эти переменные действительны в области действия этого цикла for. Например, в for (int i = 0; i < 100; ++i)
объявляется целая переменная i, которой присваивается начальное значение 0, когда начинается цикл. Эта переменная доступна для любых операторов внутри этого цикла, но она недоступна после завершения цикла. Формат 2 for (var in выражение) программныйОператор
В этом варианте цикла for задается быстрое перечисление (fast enumeration). Для переменной var можно также объявлять ее тип, что делает область ее действия локальной для данного цикла for. Выражение выражение дает результат, который подчиняется протоколу NSFastEnumeration. Обычно выражение является кол-лекцией, например, массивом или словарем.
При каждом прохождении цикла for переменной var присваивается следующий объект, полученный при начальном вычислении выражения, и выполняется тело цикла, которое представляет программныйОпзратор. Выполнение цикла за-вершается, ког да выполнен перебор всех объектов в выражении.
Отметим, что в данном цикле for нельзя изменить содержимое коллекции. Если это происходит, то создается исключение.
Для массива происходит перечисление по порядку каждого из его элементов. Для словаря происходит перечисление каждого ключа без определенного порядка. Для набора (set) происходит перечисление каждого члена набора без определенного порядка. Оператор goto
Общий формат goto идентификатор;
Выполнение оператора goto вызывает передачу управления непосредственно оператору с меткой идентификатор. Оператор с меткой должен находиться в той же функции или методе, где и goto. Оператор if Формат 1 if {выражение) программныйОператор
Если результат вычисления выражения не равен нулю, то выполняется программ-ныйОператор', иначе он пропускается. Формат 2 if (выражение) программныйОператор else программныйОператор2
Если значение выражения не равно нулю, то выполняется программныйОпера– тор1; иначе выполняется программныйОператор2. Если программный0ператор2 является еще одним оператором if, образуется цепочка if-else if, например, if {выражение1) программныйОператор else if (выражение2) программныйОператор2 else программныйОператорп
Предложение else всегда связано с последним оператором if, который не со-держит else. При необходимости можно использовать фигурные скобки, чтобы изменить эту связь. Оператор null
Общий формат ;
Выполнение null-оператора (пустого оператора) не оказывает никакого влияния и используется в основном, чтобы выполнить требование программного оператора в цикле for, do или while. В следующем операторе выполняется копирование символьной строки, указанной с помощью from, в строку, указанную с помощью to. while (*to++ = *from++ ) ;
В этом операторе используется null-оператор, чтобы выполнить требование того, что после выражения цикла while должен присутствовать программный оператор. Оператор return Формат 1 return;
Выполнение оператора return вызывает немедленный возврат выполнения программы в вызывающую функцию или метод. Этот формат можно использовать только для возврата из функции или метода, которые не возвращают никакого значения.
Если выполнение доходит до конца функции или метода, не встретив оператор return, то происходит возврат, как при выполнении оператора return в этом формате, поэтому в таком случае не возвращается никакого значения. Формат 2 return выражение;
Вызывающей функции или методу возвращается значение выражения. Если тип выражения не согласуется с типом возвращаемого значения, указанным в объявлении функции или метода, то его значение автоматически преобразуется перед возвратом в объявленный тип. Оператор switch
Общий формат switch (выражение) { case константа1: программный оператор программный оператор ... break; case кон стан та_2: программный оператор программный оператор ... break; case константап; программный оператор программный оператор ... break; default: программный оператор программный оператор ... break; } Выполняется вычисление и сравнение выражения со значениями константных выражений константа_1, константа_2, константап. Если значение выражения совпадает с одним из этих case-значений, то выполняются последующие про-граммные операторы. Если ни одно из case-значений не совпадает со значением выражения, то выполняется (если он включен) вариант по умолчанию default. Если вариант default не включен, то не выполняются никакие операторы, включенные в switch.
Результат вычисления выражения должен быть целого типа, и никакие два варианта case не должны иметь одинаковое значение. Отсутствие оператора break в определенном case-варианте вызывает продолжение выполнения в следующем case-варианте. Оператор while
Общий формат while (выражение) программныйОператор
Если значение выражения не равно нулю, выполняется программныйОператор. Поскольку выражение вычисляется каждый раз перед тем, как выполняется прог-раммныйОператор, этот оператор может никогда не выполняться. Обработка исключений
Для обработки исключений во время выполнения нужно включить операторы, которые могут генерировать исключение, в блок @try, который имеет общий формат @try программныйОператор 1 @catch (исключение) программныйОператор 2 @catch (исключение) ... @finally программныйОператор n
Если исключение выдает программныйОператор 1, то проверяются (по поряд-ку) последующие блоки @catch на совпадение соответствующего исключения с выданным исключением. Если да, то будет выполнен соответствующий программ-ныйОператор. Независимо от факта выдачи и перехвата исключения будет вы-полнен блок @finally (если он задан). Препроцессор
Препроцессор анализирует исходный файл до того, как компилятор рассмотрит сам код. Препроцессор выполняет следующие действия.
Он заменяет триграммы (группы из трех последовательных символов) на их эквиваленты (см. выше раздел «Составные операторы»).
Он объединяет в одну с троку любые строки, которые заканчиваются обратным слешем ().
Он разделяет программу на поток маркеров.
Он удаляет комментарии, заменяя их одним пробелом.
Он обрабатывает мрепроцессорные директивы (см. ниже раздел «Директивы препроцессора») и раскрывает макросы. Последовательности из триграмм
Для обработки наборов символов, не соответствующих ASCII, используются следующие трехсимвольные последовательности (триграммы), которые распоз-наются и обрабатываются специальным образом там, где они находятся в про-грамме (а также внутри символьных строк). Триграмма Значение ??= # ??( [ ??) ] ??< { ??> } ??/ ??’ ^ ??! | ??– ~ Директивы препроцессора
Все директивы препроцессора начинаются с символа #, когорый должен быть первым символом в строке, отличным от пробела. После # могут следовать один или несколько символов «пробел» или tab. Директива #define Формат 1 #define имя текст
Определяется имя идентификатора для препроцессора, это имя связывается с текстом, который начинается после первого пробела, следующего за именем, и заканчивается концом строки. При последующем использовании имени в программе оно заменяется текстом. Формат 2 #define имя (парам_ 1, парам_2,..., парам_п) текст
Определяется макрос имя, принимающий аргументы парам1, парам_2, ..., парамп, каждый из которых является идентификатором. При последующем ис-пользовании имени в программе со списком аргументов происходит подстановка текста, причем аргументы вызова этого макроса заменяют все экземпляры соответствующих параметров внутри текста.
Если макрос принимает переменное число параметров, то в конце списка аргументов используются три точки. Остальные аргументы в списке обозначаются специальным идентификатором VA_ARGS. Например, ниже определяется макрос с именем myPrintf, принимающий переменное число аргументов. #define myPrintf(...) printf («DEBUG:» _VA_ARGSJ;
Этот макрос можно использовать, например, в форме myPrintf ("Hello world!n"); или myPrintf ("i = %i, j = %in", i, j);
Если для определения требуется более чем одна строка, то для продолжения каждой строки ее нужно заканчивать символом обратного слеша. После опре-деления имени его можно использовать в любом месте данного файла.
В директивах «define, которые принимают аргументы, можно использовать оператор #, после которого следует имя аргумента. Препроцессор помещает в кавычки фактическое значение, передаваемое макросу при его вызове, то есть значение превращается в символьную строку. Например, определение #define printint(x) printf (# х "= %dn", х)
при вызове printint (count);
раскрывается препроцессором как printf ("count" "= %in", count); или эквивалентно как printf ("count = %in", count);
Препроцессор помещает символ перед любой кавычкой или символами при выполнении этой операции преобразования в строку. Например, в случае определения #define str(x) # х вызов sir (The string ,rt"contains a tab)
раскрывается следующим образом "The string "\t"contains a tab"
В директивах «define, принимающих аргументы, допускается также оператор ##. Перед ним (или после него) ставится имя аргумента для макроса. Препроцессор берет значение, передаваемое при вызове макроса, и создает один маркер из этого аргумента и из маркера, который следует за ## (или предшествует ##). Например, в случае определения макроса #define printx(n) print! ("%in", x «# n );
вызов printx (5)
дает printf ("%in", x5);
Определение #define printx(n) printf ("x"« n "= %in", x ## n );
при вызове printx(1O)
дает printf ("xIO = %in", xIO);
после подстановки и конкатенации символьных строк.
Вокруг операторов « и #« можно не ставить пробелы. Директива #error Общий формат #error текст ...
Указанный текст записывается препроцессором как сообщение об ошибке. Директива #if Формат 1 #if константное^выражение «endif
Вычисляется константное выражение. Если результат не равен нулю, то обрабаты-ваются все строки программы до директивы «endif; в противном случае они ав-томатически пропускаются и не обрабатываются препроцессором или компи-лятором. Формат 2 #if константное_выражение_1 ... #elif константное_выражение_2 ... #elif константноевыражениеп ... #else ... #endif
Если константное выражение^ не равно нулю, то обрабатываются все строки программы до #elif, а остальные строки до «endif пропускаются. В противном случае, если константное_выражение_2не равно нулю, то обрабатываются все строки программы до следующей директивы #elif, а остальные строки до «endif про-пускаются. Если все константные выражения равны нулю, то обрабатываются строки после «else (если включена эта директива).
Как часть константного выражения можно использовать специальный оператор defined. Например, при использовании #if defined (DEBUG) ... #endif
будет обрабатываться код между «if и «endif, если ранее был определен иденти-фикатор DEBUG (см. также «ifdef в следующем разделе). Идентификатор не обя-зательно заключать в круглые скобки, то есть #if defined DEBUG
действует точно так же. Директива #ifdef
Общий формат #ifdef идентификатор ... #endif
Если значение идентификатора было ранее определено (с помощью «define или опции командной строки -D при компиляции программы), то обрабатываются все строки программы до «endif; в противном случае они пропускаются. Как и в случае директивы «if, с директивой «ifdef можно использовать директивы #elif и «else. Директива #ifndef
Общий формат #ifndef идентификатор ... #endif
Если значение идентификатора не было ранее определено, то обрабатываются все строки программы до «endif; в противном случае они пропускаются. Как и в случае директивы «if, с директивой «ifndef можно использовать директивы #elif и «else. Директива # import Формат 1 #import «имяФайла»
Если файл имяФайла был ранее включен в программу, этот оператор пропус-кается. В противном случае препроцессор ищет сначала файл имяФайла в папках, которые определены реализацией. Обычно поиск начинается с той же папки, где содержится исходный файл, и если файл не найден, то выполняется поиск в последовательности стандартных мест, определенных реализацией. После того, как файл найден, его содержимое включается в программу в том месте, где находится директива «import. Препроцессорные директивы, содержащиеся во включенном файле, тоже анализируются. Поэтому сам включенный файл может содержать другие директивы «import или #include. Формат 2 #import <имяФайла>
Если этот файл не был включен ранее, препроцессор ищет его только в стан-дартных местах. В частности, текущая папка исходных файлов исключается из поиска. В остальном действия, выполняемые после того, как файл найден, иден-тичны тому, что описано выше.
При любом формате можно указать определенное ранее имя, после чего происходит раскрытие этого имени. Например, можно использовать следующую последовательность. #define ROOTOBJECT
Эта директива действует таким же образом, как #import, но не выполняется проверка предшествующего включения указанного header-файла. Директива #line
Общий формат #line константа «имяФайла»
Эта директива указывает компилятору, что последующие строки программы нужно обрабатывать в предположении, что имя исходного файла – имяФайла и что отсчет номеров строк во всех последующих строках начинается с константы. Если имяФайла не указано, то используется имя файла, указанное последней директивой «line, или имя исходного файла (если ранее не было указано никакого имени файла).
Директива «line в основном используется для задания имени файла и номера строки, которые выводятся при выдаче ошибки компилятором. Директива # pragma
Общий формат #pragma текст
Препроцессор выполнит некоторые действия, определенные реализацией. Например, «pragma loop_opt(on)
вызывает специальную оптимизацию циклов в определенном компиляторе. Если эту директиву встретит компилятор, который не распознает указание loop_opt, то она будет игнорироваться. Директива #undef
Общий формат #undef идентификатор
Указанный идентификатор станиишен неопределенным для препроцессора. Последующие директивы #ifdef или «ifndef действуют так, как будто данный иден-тификатор никогда не был определен. Директива
Это null-директива, и она игнорируется препроцессором. Заранее определенные идентификаторы
Следующие идентификаторы определены препроцессором. Идентификатор Описание LINE Номер текущей компилируемой строки. FILE Имя текущего компилируемого исходною файла. DATE Дата компилируемого файла в формате Мм дд гггг. TIME Время компилируемого файла в формате «чч:мм:сс». STDC Определен как 1, если компилятор согласуется со стандартом ANSI, и 0 в противном случае. STDC_H0STED Определен как 1, если данная реализация поддерживается (hosted), и 0 в противном случае. STDC_VERSION Определен как 199901L.
Приложение С. Исходный код адресной книги
В справочных целях здесь приводятся в полном виде файлы секций interface и implementation для примера адресной книги, с которым мы работали в части II. Сюда включены определения классов AddressCard и AddressBook. Вы должны реализовать эти классы на своем компьютере; затем определения этих классов нужно расширить, чтобы сделать их более применимыми и усилить их возможности. Для нас это станет превосходным способом изучения языка и ознакомления с созданием программ, работой с классами и объектами, а также работой с Foundation framework. Файл секции interface для AddressCard #import