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

Хорошим примером является метод arrayWithObjects: класса NSArray, который выглядит, как будто он принимает один параметр, но на самом деле он принимает любое количество параметров, разделенных запятыми. Параметры являются объектами, которые представляют собой элементы NSArray. Хитрость здесь заключается в том, что список должен заканчиваться элементом nil. Это значение не является ни одним из объектов, помещаемых в NSArray (nil не является объектом, поэтому NSArray не может его содержать), и предназначено только для того, чтобы указать, где заканчивается список.

Таким образом, вполне корректен следующий вызов этого метода:

NSArray* pep - [NSArray arrayWithObjects:@"Manny",
@"Moe", @"Jack", nil];

В объявлении метода arrayWithObjects: используется многоточие, указывающее на то, что здесь может находиться список параметров, разделенных запятыми:

+ (id)arrayWithObjects:(id)firstObj, ... ;

(Позже в этой главе я объясню смысл встречающегося в объявлении id.) Без ограничителя nil программа будет не в состоянии определить, где завершается список, и при выполнении программы могут случиться разные неприятности — ведь она заберется в поисках новых параметров туда, где их нет, и запросто заполнит NSArray всяческим мусором.

Распространенная ошибка начинающего программиста — забыть об ограничителе nil, но современный компилятор Objective-C достаточно умен, чтобы выдать предупреждение об отсутствии ограничителя — “missing sentinel in method dispatch”. Несмотря на то что это всего лишь предупреждение, не запускайте такой код на выполнение! Еще один способ не забыть об ограничителе nil в этом конкретном примере — избежать вызова arrayWithObjects : вообще, что возможно начиная с версии компилятора LLVM 4.0 (Xcode 4.4 или более поздний), где вы можете образовать литеральный объект NSArray непосредственно, с помощью синтаксиса @ [.. . ]:

NSArray* pep - @[@"MannyM, @"Мое'\ 8"Jack"];

Это просто упрощенная запись, которая “за кулисами" разворачивается в вызов arrayWithObjects:, но этот вызов корректно оформлен, с ограничителем nil, так что шансов не допустить ошибку у программиста существенно больше, чем при явном вызове arrayWithObjects: (да и количество вводимых символов при этом куда меньше).

Тем не менее вы будете встречаться со многими другими методами Objective-C, которые принимают параметр, являющийся списком переменной длины с завершающим nil. Например, у протокола UIAppearance имеется метод класса appearanceWhenContainedln: или метод initWithTitle:message:delegate:cancelButtonTitle:otherButtonTi ties: в UIAlertView. Жаль, что Apple не изменит каким-то образом Objective-C (или эти методы), чтобы избежать использования ограничителя nil; но до тех пор, пока это не сделано, следует знать, как правильно вызываются такие методы.

Язык С явным образом обеспечивает функционирование списков аргументов неопределенной длины, чем методы Objective-C наподобие arrayWithObjects: пользуются “за сценой”. Я не собираюсь пояснять работу механизма языка программирования С, поскольку не думаю, что вам придется писать метод или функцию, для которых он потребуется. Но если вам нужны соответствующие подробности — обратитесь к K&R 7.3.


 

 

 

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