Существуют ли строго типизированные коллекции в Objective-C? - PullRequest
138 голосов
/ 11 мая 2009

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

Dictionary<int, MyCustomObject>

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

Ответы [ 11 ]

209 голосов
/ 09 июня 2015

В 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'

Облегченные обобщенные типы предназначены для использования с 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

91 голосов
/ 11 мая 2009

Этот ответ устарел, но остается для исторической ценности. Начиная с Xcode 7, ответ Коннора от 8 июня 15 года более точный.


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

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

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

11 голосов
/ 20 ноября 2010

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

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

или

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
6 голосов
/ 09 июня 2015

Apple добавила дженерики в ObjC в XCode 7:

@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;

см. Здесь: https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6-ID61

6 голосов
/ 11 мая 2009

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

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

Массивы - это упорядоченные наборы объектов. Какао предоставляет несколько классов массивов, NSArray, NSMutableArray (подкласс NSArray) и NSPointerArray.

5 голосов
/ 09 июня 2015

Это было выпущено в 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];

Будьте осторожны с этими * с.

4 голосов
/ 14 марта 2013

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

- (id)objectAtIndex:(NSUInteger)index

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

@interface NSStringArray : NSArray

в

- (NSString *)objectAtIndex:(NSUInteger)index

для NSArray, содержащего только строки NSS.

Созданный подкласс может использоваться в качестве замены для вставки и содержит много полезных функций: предупреждения компилятора, доступ к свойствам, лучшее создание кода и -заполнение в 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>, но вы можете выбрать собственную схему именования, чтобы пометить их как классы как шаблоны.

2 голосов
/ 16 июня 2015

Просто хочу прыгнуть сюда. Я написал пост в блоге здесь о дженериках.

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

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

Наслаждайтесь.

2 голосов
/ 09 июня 2015

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

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

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

2 голосов
/ 01 августа 2013

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

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

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

...