Есть ли что-то вроде общего списка в Cocoa/Objective-C?

То, что мне действительно нравится в С#, - это общие списки. Список, который может содержать только один тип объектов. Есть ли что-то вроде общего списка в Cocoa/Objective-C? Насколько я знаю только NSArray, кто возьмет указатель на любой объект.

Ответ 1

Желание этого в приложении Cocoa часто является признаком слабого дизайна.

NSArray является неизменным, поэтому он не будет "принимать указатель на любой объект" и, по-видимому, уже содержит правильные объекты, когда вы им передаете. Я полагаю, что вас больше беспокоит - это NSMutableArray, где, по вашему мнению, другие части вашего кода могут добавить неправильный тип объекта. Но посмотрите на Cocoa; невероятно редко выставлять изменчивый массив как часть дизайна класса.

Вместо этого вы обычно показываете NSArray и пару методов для изменения этого массива. Что-то вроде:

@class Foo : NSObject
- (NSArray *)bars;
- (void)addBar:(Bar *)bar;
- (void)removeBar:(Bar *)bar;
@end

Это обычно останавливает неправильные объекты, вставленные просто с помощью предупреждения компилятора, и, конечно, вы можете добавить утверждения в -addBar: и -removeBar:, если хотите.

Ответ 2

Objective-C не поддерживает общее программирование. Вы всегда можете использовать Objective-C ++ и список STL.

Ответ 3

Общие NSArrays могут быть реализованы путем подклассификации NSArray и переопределения всех предоставленных методов с более ограничительными. Например,

- (id)objectAtIndex:(NSUInteger)index

нужно было бы переопределить в

@interface NSStringArray : NSArray

а

- (NSString *)objectAtIndex:(NSUInteger)index

чтобы NSArray содержал только NSStrings.

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

Можно автоматизировать это и свести его до двух операторов, что приближает его к языкам, поддерживающим дженерики. Я создал автоматизацию с WMGenericCollection, где шаблоны предоставляются как макросы C препроцессора.

После импорта файла заголовка, содержащего макрос, вы можете создать общий NSArray с двумя операторами: один для интерфейса и один для реализации. Вам нужно только указать тип данных, который вы хотите сохранить, и имена для ваших подклассов. WMGenericCollection предоставляет такие шаблоны для NSArray, NSDictionary и NSSet, а также их изменяемые копии.

Ответ 4

Нет, Objective-C в настоящее время не поддерживает параметрическую типизацию для элементов коллекции.

Однако эта тема сложнее, чем вопрос или существующие ответы допускают.

Параметрический ввод для коллекций в Objective-C не будет таким же, как Generics в С#/Java. Например, маловероятно, что вы когда-нибудь увидите Objective-C добавьте возможность гарантировать, что каждый объект, добавленный в коллекцию, является типом или подтипом NSArray. Вместо этого Objective-C может (и IMO) иметь возможность гарантировать каждому объекту в коллекции CONFORMS протокол/интерфейс. (то есть, что он реализует набор требуемых методов)

Почему?

Objective-C - это язык, основанный на совместимости протокола (интерфейса), а не подтипы. То есть, объекты совместимы, если у них есть все правильные методы, мы не смотрим на их фактические типы и не заботимся о них. Фактически, глядя на фактические типы, это очень плохая практика в Obj-C и в крайне обескураженной. Это понятие иногда называют "Duck Typing", потому что, если оно окунается, как утка, это утка. Нам все равно, если это буквально унаследовано от какой-то определенной утки или нет. Это мешает вам быть обремененным иерархией реализации elses. - Результат состоит в том, что до тех пор, пока объект, выходящий из списка, имеет метод draw::, он работает, на самом деле нам неинтересно, является ли он подклассом определенного объекта JimmyDrawableBase.

Это не только делает код более многоразовым, но также поощряет несколько иной (более функциональный?) тип декомпозиции проблемы, поскольку вы не можете полагаться на объекты, получаемые из данного базового класса, и, таким образом, иметь кучу ваших принудительная реализация в базовом классе.

Я лично считаю, что компилятору Obj-C было бы неплохо иметь параметрическую проверку PROTOCOL * CONFORMANCE *. То есть, чтобы создать NSMutableArray, который требует, чтобы все объекты, помещенные в него, соответствовали данному протоколу (т.е. Имели заданный набор необходимых методов).

Иногда даже этой более гибкой проверке соответствия протокола противостоят люди динамического программирования и по здравым соображениям. Программисты часто имеют способ чрезмерного определения требований к соответствию.

Например, вам может потребоваться, чтобы список содержал объекты, соответствующие протоколу/интерфейсу NSArray, но вы можете просто вызвать только два из этих методов. Это чрезмерное соответствие. Кто-то, кто хочет вставить совместимый элемент в ваш массив, вынужден реализовать тонну методов, которые вы на самом деле не вызываете, по крайней мере, пока (см. Далее).

Google Go пытается решить эту проблему, вызывая структурную совместимость. То есть, если вы вызываете draw() для элементов, выходящих из списка, тогда компилятор гарантирует, что все входящее в список содержит метод draw(). Если он не содержит метод draw(), это ошибка компилятора, чтобы поместить его в список. Это предотвращает простое выполнение кода во время выполнения. Проблема в том, что он работает только для компиляции всей программы. Если Google-Go мог бы скомпилировать модульные библиотеки DLL (что не может), тогда возникла бы проблема, что мне нечего сказать, что объекты в списке должны поддерживать определенный интерфейс из трех методов, хотя Я не звоню им сегодня, потому что я могу назвать их в будущем.

Между этими двумя решениями нравится компромисс и правда.

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

Мне также хотелось бы, чтобы компилятор помог мне избежать чрезмерного соответствия. Если я не вызываю методы в этих протоколах на объектах, он должен генерировать ошибки/предупреждения, рассказывающие мне об этом. Если я хочу сохранить их в протоколе, хотя я их не использую, мне нужно будет явно сделать декларацию для каждого метода в протоколе, что она "может быть использована в будущем, поэтому все элементы должны ее предоставить сейчас" ". Это, по крайней мере, делает процесс чрезмерного соответствия требованиям MORE, вместо Java/С#, где требуется меньше работы.