Язык Objective-C переполнен указателями (и звездочками), поскольку именно так он обращается к объектам. Методы Objective-C работают в основном с объектами, так что обычно они ожидают параметры-указатели и возвращают значения-указатели.

Но это не усложняет программирование. Указатели — это то, что ожидает Objective-C, но одновременно это и то, что Objective-C дает вам. Так что никаких особых проблем не наблюдается.

Например, можно объединить две строки NSString с помощью вызова метода stringByAppendingString: объекта NSString. Документация говорит нам, что этот метод объявлен следующим образом:

- (NSString *)stringByAppendingString:(NSString *)aString

Это объявление говорит всем, кто понимает синтаксис Objective-C, что метод ожидает один параметр типа NSString* и возвращает значение типа NSString*. Это звучит неприятно, но все в порядке, поскольку каждый объект NSString на самом деле представляет собой NSString*. Так что не может быть ничего проще, чем получить новую строку NSString, состоящую из двух соединенных строк:

NSString* si = @"Hello,
NSString* s2 = @"World!";
NSString* s3 = [si StringByAppendingString: s2];

Однако иногда функция или метод ожидает в качестве параметра указатель на что-то; при этом у нас есть это “что-то”, но нет указателя на него. Решение заключается в применении оператора получения адреса (K&R 5.1), который представляет собой амперсанд, размещенный перед именем объекта, адрес которого нам нужен.

Например, имеется метод класса NSString для чтения из файла в объект класса NSString, который объявляется следующим образом:

+ (id)stringWithContentsOfFile:(NSString *)path
encoding:(NSStringEncoding)enc error:(NSError **)error

He будем пока что беспокоиться о том, что такое id, и о синтаксисе объявления методов в языке Objective-C. Просто рассмотрим типы параметров. Первый из них — NSString*; здесь нет никаких проблем, поскольку каждая ссылка на NSString в действительности является

указателем на объект типа NSString. NSStringEncoding оказывается просто другим именем примитивного типа данных, NSUInteger, так что и здесь нет никаких проблем. Но что такое NSError**?

По логике NSError** должно быть указателем на указатель на NSError. И это в самом деле так. Этот метод требует передачи ему указателя на указатель на NSError. Объявить указатель на NSError легко:

 

NSError* err;

Но как получить указатель на этот указатель? С помощью оператора взятия адреса! Так что схематически наш код может выглядеть следующим образом:

NSString* path •  II  Что-то там
NSStringEncoding enc = II Что-то там
NSError* err = nil;
NSString* result =
[NSString stringWithContentsOfFile: path
encoding: enc error: Serr];

Следует отметить важную вещь об амперсанде. Поскольку err является указателем на NSError, &err представляет собой указатель на указатель на NSError, именно то, что нам и надо обеспечить. Таким образом, все получается как надо. В главе 3, мы обсудим, как вы должны использовать возвращаемый результат и значение err после вызова метода.

Оператор взятия адреса можно использовать для создания указателя на любую именованную переменную. Функция С технически является своего рода именованной переменной, так что можно создать даже указатель на функцию! Это пример того, когда имя функции используется без скобок: в этом случае мы не вызываем функцию, а просто говорим о ней. Например, & square представляет собой указатель на функцию square. Кроме того, так же, как неявно имя массива без индекса является указателем на его первый элемент, так и имя функции без скобок неявно является указателем на функцию; оператор взятия адреса при этом является необязательным. В главе 3, описана ситуация, в которой указатель на функцию оказывается очень полезной вещью.


 

 

 

Добавить комментарий