Почему NSArray arrayWithObjects требует завершающий ноль?

Я понимаю, что это знаменует собой конец набора varargs, но почему он не может быть реализован таким образом, что не требует ноль?

Ответы на вопрос(6)

Решение Вопроса

Рассмотрим эти методы:

- (id)initWithFormat:(NSString *)format, ...;
+ (id)arrayWithObjects:(id)firstObj, ...;
+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;

... сообщает компилятору, что может присутствовать переменное число аргументов любого типа. Компилятор не может знать, какими должны быть эти типы (в реальных определениях есть маркеры, которые помогают с этим).

Теперь рассмотрим три метода. Все три имеют совершенно разные требования к тому, что может присутствовать в списке переменных аргументов. Массивдолжен быть кучей объектов, за которыми следует ноль. Словарь требует несколько пар объектов, за которыми следует ноль. Наконец, строковый метод требует группы аргументов, которые соответствуют типам в строке формата.

Все эти варианты поведения напрямую связаны с вызываемым методом, и, если автор API решит пойти на «сложный в использовании», поведение декодирования переменных аргументов может быть изменено во время выполнения, просто чтобы усложнить жизнь.

Итог: C ABI не имеет синтаксиса, который позволяет указывать, что метод или функция принимает переменное число аргументов с любым набором ограничений на аргументы или их завершение.

Objective-C может изменить правила только для объявлений и вызовов методов, но это не поможет с функциями C или C ++, с которыми Objective-C должен оставаться совместимым.

 NSResponder06 сент. 2009 г., 16:20
Кен, помещая особые случаи в компилятор для определенных классов, таких как NSArray, открывает огромную банку червей. Что делать, если вы подкласс NSArray?
 Ken26 авг. 2009 г., 12:22
Кажется, что компилятор мог бы прозрачно добавить конечный ноль к [NSArray arrayWithObjects: a, b, c]. Это привело бы к тому, что ноль не будет допущен в качестве аргумента. Мы могли бы даже сделать это сейчас. Люди, которые уже включают nil, просто получают [NSArray arrayWithObjects: a, b, c, nil, nil], что, я думаю, не смертельно.
 mipadi25 авг. 2010 г., 22:20
@ Кен: Вы не можете добавитьnil чтобыNSArray в любом случае (вы должны использоватьNSNull вместо).

тейнеров) в Objective-C. Видетьhttp://clang.llvm.org/docs/ObjectiveCLiterals.html

что за кулисами это цикл for, который будет продолжать принимать аргументы отva_list пока не достигнетnil, Таким образом, конечным условием могло быть что угодно, например, строка «стоп». Ноnil на самом деле довольно умный.

Допустим, у нас есть три объектаhansel, gretel а такжеwoodcutter и создайте их массив:

NSArray *startCharacters = [NSArray arrayWithObjects:hansel, gretel, woodcutter, nil];

Теперь мы понимаем, чтоwoodcutter никогда не был инициирован, так что этоnil, ноstartCharacters все еще будет создан сhansel а такжеgretel объекты, так как, когда он достигаетwoodcutter это заканчивается. Таким образом, ноль-окончание вarrayWithObjects: предотвращает сбой приложения.

Если вам не нравится выписыватьnil вы всегда можете создать массив следующим образом:

NSArray *startCharacters = @[hansel, gretel, woodcutter];

Это действительно, это короче, но это потерпит крах, если объектnil, Итак, вывод таков, чтоarrayWithObjects: все еще может быть очень полезным, и вы можете использовать его в своих интересах.

но мой любимый в настоящее время больше подходит для приложений, чем для выпущенных фреймворков. Примите NSArray в вашем методе вместо «...», а затем заполните его вспомогательным макросом ниже, который находится в вашем файле префикса или заголовке утилиты.

#define $ array (objs ...) [NSArray arrayWithObjects: objs, nil]

Это позволит использовать несколько хорошо помеченных аргументов переменной длины, и вы избавите себя от архаичной схемы необходимости использовать первый аргумент, а затем va_list и его братьев в пользу цикла for-in или многих других доступных инструментов сбора.

[self findMatchingSetAndAlert: @ "title" связей: $ массив (tie1, tie2, tie3) рубашки: $ массив (рубашка1, рубашка2, рубашка3, рубашка4)];

Если кто-то знает, как реализовать список без разделителей, такой как stringWithFormat, сообщите нам об этом! Он использует атрибуты и макросы или что-то, разработанное специально для форматирования, но они реализованы как-то.

 Peter DeWeese02 июн. 2014 г., 16:19
Мой ответ довольно старый, и макросы больше не нужны в качестве костыля. Современный синтаксис Objective C очень помогает, так как теперь вы можете создать массив@[@"firstString", @"secondString"], Теперь мы можем беспокоиться о типах вместо синтаксической церемонии.

сколько параметров присутствует - если вы не завершите nil, вам просто нужно что-то еще. В этом случае очевидной альтернативой является длина, но тогда вам нужно будет обновлять аргумент длины каждый раз, когда вы меняете количество элементов в массиве, и это может быть громоздким или, что еще хуже, сломанным.

Я предполагаю, что у вас есть массив, который может содержать ноль?

 pjb321 авг. 2009 г., 05:07
Это не так уж и сложно - забыть о нулевом терминаторе, просто я привык к другим языкам, таким как Java и Ruby, которые допускают переменные без нулевого терминатора. Может быть, я спрашиваю, почему Obj-C требует нулевого терминатора для varargs? Почему компилятор не может просто «делать правильные вещи» для [NSArray arrayWithObjects: @ "foo", @ "bar"]? Мой вопрос - скорее вопрос любопытства, почему язык требует этого. Это очевидная бородавка при переходе с других языков. Это потому что varargs для функций C?
 Chuck21 авг. 2009 г., 03:13
NSArray не может содержать nil - вы должны использовать NSNull для его представления. Я предполагаю, что он только что был укушен раздражающими ошибками, которые могут возникнуть из-за забвения нулевого терминатора.
 olliej21 авг. 2009 г., 05:26
I верить varargs target-c построены на стандартных varargs C, которые не передают количество аргументов. Вероятно, obj-c мог бы сделать это в своей первоначальной реализации, но теперь он связан с совместимостью ABI.
 Chuck21 авг. 2009 г., 18:14
Да, нет никаких специальных Varargs Objective-C. Это просто ванильные варарги со всеми неприятностями, которые приходят вместе с ним.
 NSResponder21 авг. 2009 г., 05:28
OllieJ правильно. Имейте в виду, что obj-C - это правильный надмножество языка C. То, что вы предлагаете, - это введение в компилятор особого случая, когда он должен заботиться о том, какой класс и селектор вы используете.

@bbum дает некоторые технические детали.почему они не исправляют это?"

Помните: C - просто ассемблер, а Obj-C - просто C ... Конечно, он может быть переработан, но на это почти нет давления. Вы все еще не можете поместить nil в массив (это потребует огромных изменений). Теперь компилятор предупреждает вас, если вы забыли ноль, так что разработчики не часто жалуются на это. Компромисс делает язык намного (намного!) Более простым, чем его род, получая преимущества десятилетий оптимизации компилятора C и гарантированной совместимости с кодом C.

Одна вещь, которая должна стать понятной из обсуждения @ bbum: NSArray не является языковой особенностью Objective-C. C-массивы - это языковая функция, но NSArrays - это просто другой объект, не отличающийся от объектов, которые вы пишете.

Ваш ответ на вопрос