Имеются ли строго типизированные коллекции в Objective-C?

Я новичок в программировании на Mac/iPhone и Objective-C. В С# и Java у нас есть "generics", классы коллекции, члены которых могут быть только объявленного типа. Например, в С#

Dictionary<int, MyCustomObject>

может содержать только ключи, которые являются целыми числами и значениями типа MyCustomObject. Существует ли аналогичный механизм в Objective-C?

Ответ 1

В Xcode 7 Apple представила "Легкие генераторы" до Objective-C. В Objective-C они будут генерировать предупреждения компилятора, если существует несоответствие типов.

NSArray<NSString*>* arr = @[@"str"];

NSString* string = [arr objectAtIndex:0];
NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *'

И в коде Swift они выдадут ошибку компилятора:

var str: String = arr[0]
var num: Int = arr[0] //Error 'String' is not convertible to 'Int'

Легкие Generics предназначены для использования с NSArray, NSDictionary и NSSet, но вы также можете добавить их в свои собственные классы:

@interface GenericsTest<__covariant T> : NSObject

-(void)genericMethod:(T)object;

@end

@implementation GenericsTest

-(void)genericMethod:(id)object {}

@end

Objective-C будет вести себя так, как раньше, с предупреждениями компилятора.

GenericsTest<NSString*>* test = [GenericsTest new];

[test genericMethod:@"string"];
[test genericMethod:@1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'

но Swift полностью игнорирует общую информацию. (Больше не действует в Swift 3 +.)

var test = GenericsTest<String>() //Error: Cannot specialize non-generic type 'GenericsTest'

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

Взаимодействие с API Objective-C

Ответ 2

Этот ответ устарел, но остается для исторического значения. Что касается Xcode 7, то ответ Коннора от 8 июня '15 более точным.


Нет, в Objective-C нет дженериков, если вы не хотите использовать шаблоны С++ в своих собственных классах коллекций (которые я категорически отвергаю).

Objective-C имеет динамическую типизацию как функцию, что означает, что среда выполнения не заботится о типе объекта, поскольку все объекты могут получать сообщения. Когда вы добавляете объект во встроенную коллекцию, они обрабатываются так, как если бы они были типа id. Но не волнуйтесь, просто отправляйте сообщения этим объектам, как обычно; он будет работать нормально (если, конечно, один или несколько объектов в коллекции не отвечают на отправляемое сообщение).

В таких языках, как Java и С#, необходимы обобщения, поскольку они являются сильными, статически типизированными языками. Полностью отличная игра, отличная от Objective-C динамической типизации.

Ответ 3

Нет, но для того, чтобы сделать его более понятным, вы можете прокомментировать его с типом объекта, который хотите сохранить, я видел это несколько раз, когда вам нужно что-то написать в Java 1.4 в настоящее время), например:

NSMutableArray* /*<TypeA>*/ arrayName = ....

или

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...

Ответ 4

В Objective-C нет дженериков.

Из Документов

Массивы представляют собой упорядоченные коллекции объектов. Cocoa содержит несколько классов массивов, NSArray, NSMutableArray (подкласс NSArray) и NSPointerArray.

Ответ 6

Это было выпущено в Xcode 7 (наконец!)

Обратите внимание, что в коде Objective C это просто проверка времени компиляции; не будет ошибки во время выполнения только для того, чтобы поместить неправильный тип в коллекцию или присвоить типизированное свойство.

Declare:

@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end

Использование:

FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];

Будьте внимательны к тем * s.

Ответ 7

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

- (id)objectAtIndex:(NSUInteger)index

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

@interface NSStringArray : NSArray

а

- (NSString *)objectAtIndex:(NSUInteger)index

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

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

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

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

Пример: List<int> может быть реализован пользовательским классом под названием NumberArray, который создается со следующим выражением:

WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class
                         // generated class names
                         NumberArray, MutableNumberArray)

Как только вы создали NumberArray, вы можете использовать его везде в своем проекте. В нем отсутствует синтаксис <int>, но вы можете выбрать свою собственную схему именования, чтобы обозначать их как классы как шаблоны.

Ответ 8

Взгляните на:

https://github.com/tomersh/Objective-C-Generics

Похоже, что это своего рода недоброжелатели, перепрофилировав механизм проверки протокола.

Ответ 9

Теперь сбываются мечты - в настоящее время есть дженерики в Objective-C (спасибо, WWDC). Это не шутка - на официальная страница Swift:

Новые синтаксические функции позволяют писать более выразительный код, улучшая согласованность языка. SDK использовали новые функции Objective-C, такие как дженерики и аннотацию нулевой вероятности, чтобы сделать код Swift еще более чистым и безопасным. Вот только выборка улучшений Swift 2.0.

И изображение, которое подтверждает это: Objective-C generics

Ответ 10

Просто прыгай сюда. Я написал сообщение в блоге здесь о Generics.

Вещь, которую я хочу внести, заключается в том, что Generics могут быть добавлены в любой класс, а не только классы коллекции, как указывает Apple.

Я успешно добавил к различным классам, поскольку они работают точно так же, как и коллекции Apple. то есть. проверка времени компиляции, завершение кода, возможность удаления следов и т.д.

Enjoy.

Ответ 11

Классы коллекций, предоставляемые инфраструктурами Apple и GNUStep, являются полу-родовыми, поскольку они предполагают, что им предоставляются объекты, некоторые из которых являются сортируемыми, а некоторые, которые отвечают на определенные сообщения. Для примитивов, таких как float, ints и т.д., Вся структура массивов C неповреждена и может быть использована, и для них существуют специальные объекты-обертки для использования в общих классах коллекций (например, NSNumber). Кроме того, класс Collection может быть подклассифицирован (или специально изменен через категории), чтобы принимать объекты любого типа, но вы должны сами написать весь код обработки кода. Сообщения могут быть отправлены на любой объект, но должны возвращать значение null, если оно не подходит для объекта, или сообщение должно быть отправлено соответствующему объекту. Ошибки True-типа должны быть обнаружены во время компиляции, а не во время выполнения. Во время выполнения они должны обрабатываться или игнорироваться. Наконец, Objc предоставляет средства анализа времени выполнения для обработки сложных случаев, а ответ сообщения, определенный тип и службы могут быть проверены на объекте до того, как оно будет отправлено сообщение или помещено в неподходящую коллекцию. Помните, что разрозненные библиотеки и фреймворки принимают различные соглашения о том, как их объекты ведут себя, когда отправляются сообщения, на которые они не имеют ответов на код, поэтому RTFM. Помимо программ для игрушек и отладочных сборников, большинству программ не приходится сталкиваться, если они действительно не испортили и не пытались записать плохие данные в память или диск, выполнять незаконные операции (например, делить на ноль, но вы тоже можете их поймать), или получить доступ отключить системные ресурсы. Динамичность и время выполнения Objective-C позволяют делать вещи неудачно изящно и должны быть встроены в ваш код. (СОВЕТ), если у вас возникают проблемы с универсальностью в ваших функциях, попробуйте определенную специфику. Запишите функции с определенными типами и позвольте времени выполнения выбрать (именно поэтому они называются селекторами!) Соответствующую функцию-член во время выполнения.

Example:
    -(id) sort (id) obj;  // too generic. catches all.
     // better
    -(id) sort: (EasilySortableCollection*) esc;
    -(id) sort: (HardToSortCollection*) hsc; 
    ...
    [Sorter  sort: MyEasyColl];
    [Sorter  sort: MyHardColl];