Поддерживает ли Objective-C Generics?

Интересно, предлагает ли Objective-C любую поддержку для дженериков?

Например, рассмотрим метод:

-(void) sort: (NSMutableArray *) deck { } 

Есть ли какой-нибудь способ для меня сделать это только с колодой карт?
Есть что-то вроде этого, чтобы обеспечить соблюдение?

 -(void) sort: (NSMutableArray ) deck { } 

Вы можете использовать инструменты интроспекции, предлагаемые средой объектива-c.

В основном это означает, что вы можете проверить, являются ли все объекты в массиве либо своего рода classом (class A, либо один его подclass), либо членом classа (class A), либо если объекты соответствуют протоколу или отвечают на селектор (имеется определенный метод).

 -(void) sort: (NSMutableArray *) deck { for(id obj in deck){ if(obj isKindOfClass:[A class]]){ //this is of right class } } } 

Вы можете написать метод Category в NSArray который NSArray это на каждом объекте.

 BOOL allAreKindOfA = [array allObjectsAreKindOfClass:[A class]]; 

Обычно вам это очень часто не нужно, поскольку вы знаете, что вы вкладываете в коллекцию.

Если вам нужно проверить тип или способность объекта в массиве, это может быть индикатором того, что ваша архитектура нарушена


Другим вариантом может быть подclass NSMutableArray который принимает только определенные classы. Но имейте в виду подclassы для NSMutableArray и NSArray , так как это кластеры classов и, следовательно, нелегкие подclassы.

Примечание. В моем другом ответе я создал подclass NSMutableArray , который использует блок для проверки, если выполняется определенное требование. Если вы протестуете против членства в classе, это будет делать именно то, что вы хотите. Используйте второй блок для обработки ошибок.

Объектив C поддерживает Generics теперь, с XCode 7.

Компилятор XCode 7 предоставит вам предупреждение компилятора, если существует несоответствие типа.

Например, следующая строка поднимет предупреждение компилятора, поскольку второй объект в массиве вызывает несоответствие типов. Массив позволяет использовать только объекты NSString .

 NSArray  *myArray = [@"str2", @1, @"str2"]; 

Начиная с версии Xcode 7, Apple добавила поддержку дженериков Objective-C.

 NSArray  *arrayOfStrings = @[@"a", @"b"]; NSDictionary  *dictionaryOfDates = @{ @"a" : @1 }; 

Вдохновленный MonomorphicArray, я придумал еще одну идею:

Создайте подclass в NSMutableArray, который занимает два блока:

  • AddBlock – блок, который тестирует, если одно или несколько требований заполнены полностью и добавляет объект только, если его проходит тест
  • FailBlock – блок, который определяет, что происходит, если тест не был успешным.

AddBlock может тестировать определенное членство classа, например

 ^BOOL(id element) { return [element isKindOfClass:[NSString class]]; } 

и FailBlock может вызвать исключение, выйти из строя или добавить элемент, который не прошел тест, в другой массив. Если ни один failBlock не предоставлен, блок по умолчанию вызывает ошибку.

Блоки будут определять, если массив действует как общий массив или как фильтр.
Я приведу полный пример для второго случая.

VSBlockTestedObjectArray.h

 #import  typedef BOOL(^AddBlock)(id element); typedef void(^FailBlock)(id element); @interface VSBlockTestedObjectArray : NSMutableArray @property (nonatomic, copy, readonly) AddBlock testBlock; @property (nonatomic, copy, readonly) FailBlock failBlock; -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock Capacity:(NSUInteger)capacity; -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock; -(id)initWithTestBlock:(AddBlock)testBlock; @end 

VSBlockTestedObjectArray.m

 #import "VSBlockTestedObjectArray.h" @interface VSBlockTestedObjectArray () @property (nonatomic, retain) NSMutableArray *realArray; -(void)errorWhileInitializing:(SEL)selector; @end @implementation VSBlockTestedObjectArray @synthesize testBlock = _testBlock; @synthesize failBlock = _failBlock; @synthesize realArray = _realArray; -(id)initWithCapacity:(NSUInteger)capacity { if (self = [super init]) { _realArray = [[NSMutableArray alloc] initWithCapacity:capacity]; } return self; } -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock Capacity:(NSUInteger)capacity { self = [self initWithCapacity:capacity]; if (self) { _testBlock = [testBlock copy]; _failBlock = [failBlock copy]; } return self; } -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock { return [self initWithTestBlock:testBlock FailBlock:failBlock Capacity:0]; } -(id)initWithTestBlock:(AddBlock)testBlock { return [self initWithTestBlock:testBlock FailBlock:^(id element) { [NSException raise:@"NotSupportedElement" format:@"%@ faild the test and can't be add to this VSBlockTestedObjectArray", element]; } Capacity:0]; } - (void)dealloc { [_failBlock release]; [_testBlock release]; self.realArray = nil; [super dealloc]; } - (void) insertObject:(id)anObject atIndex:(NSUInteger)index { if(self.testBlock(anObject)) [self.realArray insertObject:anObject atIndex:index]; else self.failBlock(anObject); } - (void) removeObjectAtIndex:(NSUInteger)index { [self.realArray removeObjectAtIndex:index]; } -(NSUInteger)count { return [self.realArray count]; } - (id) objectAtIndex:(NSUInteger)index { return [self.realArray objectAtIndex:index]; } -(void)errorWhileInitializing:(SEL)selector { [NSException raise:@"NotSupportedInstantiation" format:@"not supported %@", NSStringFromSelector(selector)]; } - (id)initWithArray:(NSArray *)anArray { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithContentsOfFile:(NSString *)aPath{ [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithContentsOfURL:(NSURL *)aURL{ [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithObjects:(id)firstObj, ... { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithObjects:(const id *)objects count:(NSUInteger)count { [self errorWhileInitializing:_cmd]; return nil;} @end , #import "VSBlockTestedObjectArray.h" @interface VSBlockTestedObjectArray () @property (nonatomic, retain) NSMutableArray *realArray; -(void)errorWhileInitializing:(SEL)selector; @end @implementation VSBlockTestedObjectArray @synthesize testBlock = _testBlock; @synthesize failBlock = _failBlock; @synthesize realArray = _realArray; -(id)initWithCapacity:(NSUInteger)capacity { if (self = [super init]) { _realArray = [[NSMutableArray alloc] initWithCapacity:capacity]; } return self; } -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock Capacity:(NSUInteger)capacity { self = [self initWithCapacity:capacity]; if (self) { _testBlock = [testBlock copy]; _failBlock = [failBlock copy]; } return self; } -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock { return [self initWithTestBlock:testBlock FailBlock:failBlock Capacity:0]; } -(id)initWithTestBlock:(AddBlock)testBlock { return [self initWithTestBlock:testBlock FailBlock:^(id element) { [NSException raise:@"NotSupportedElement" format:@"%@ faild the test and can't be add to this VSBlockTestedObjectArray", element]; } Capacity:0]; } - (void)dealloc { [_failBlock release]; [_testBlock release]; self.realArray = nil; [super dealloc]; } - (void) insertObject:(id)anObject atIndex:(NSUInteger)index { if(self.testBlock(anObject)) [self.realArray insertObject:anObject atIndex:index]; else self.failBlock(anObject); } - (void) removeObjectAtIndex:(NSUInteger)index { [self.realArray removeObjectAtIndex:index]; } -(NSUInteger)count { return [self.realArray count]; } - (id) objectAtIndex:(NSUInteger)index { return [self.realArray objectAtIndex:index]; } -(void)errorWhileInitializing:(SEL)selector { [NSException raise:@"NotSupportedInstantiation" format:@"not supported %@", NSStringFromSelector(selector)]; } - (id)initWithArray:(NSArray *)anArray { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithContentsOfFile:(NSString *)aPath{ [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithContentsOfURL:(NSURL *)aURL{ [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithObjects:(id)firstObj, ... { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithObjects:(const id *)objects count:(NSUInteger)count { [self errorWhileInitializing:_cmd]; return nil;} @end , #import "VSBlockTestedObjectArray.h" @interface VSBlockTestedObjectArray () @property (nonatomic, retain) NSMutableArray *realArray; -(void)errorWhileInitializing:(SEL)selector; @end @implementation VSBlockTestedObjectArray @synthesize testBlock = _testBlock; @synthesize failBlock = _failBlock; @synthesize realArray = _realArray; -(id)initWithCapacity:(NSUInteger)capacity { if (self = [super init]) { _realArray = [[NSMutableArray alloc] initWithCapacity:capacity]; } return self; } -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock Capacity:(NSUInteger)capacity { self = [self initWithCapacity:capacity]; if (self) { _testBlock = [testBlock copy]; _failBlock = [failBlock copy]; } return self; } -(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock { return [self initWithTestBlock:testBlock FailBlock:failBlock Capacity:0]; } -(id)initWithTestBlock:(AddBlock)testBlock { return [self initWithTestBlock:testBlock FailBlock:^(id element) { [NSException raise:@"NotSupportedElement" format:@"%@ faild the test and can't be add to this VSBlockTestedObjectArray", element]; } Capacity:0]; } - (void)dealloc { [_failBlock release]; [_testBlock release]; self.realArray = nil; [super dealloc]; } - (void) insertObject:(id)anObject atIndex:(NSUInteger)index { if(self.testBlock(anObject)) [self.realArray insertObject:anObject atIndex:index]; else self.failBlock(anObject); } - (void) removeObjectAtIndex:(NSUInteger)index { [self.realArray removeObjectAtIndex:index]; } -(NSUInteger)count { return [self.realArray count]; } - (id) objectAtIndex:(NSUInteger)index { return [self.realArray objectAtIndex:index]; } -(void)errorWhileInitializing:(SEL)selector { [NSException raise:@"NotSupportedInstantiation" format:@"not supported %@", NSStringFromSelector(selector)]; } - (id)initWithArray:(NSArray *)anArray { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithContentsOfFile:(NSString *)aPath{ [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithContentsOfURL:(NSURL *)aURL{ [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithObjects:(id)firstObj, ... { [self errorWhileInitializing:_cmd]; return nil;} - (id)initWithObjects:(const id *)objects count:(NSUInteger)count { [self errorWhileInitializing:_cmd]; return nil;} @end 

Используйте его так:

 VSBlockTestedObjectArray *stringArray = [[VSBlockTestedObjectArray alloc] initWithTestBlock:^BOOL(id element) { return [element isKindOfClass:[NSString class]]; } FailBlock:^(id element) { NSLog(@"%@ can't be added, didn't pass the test. It is not an object of class NSString", element); }]; VSBlockTestedObjectArray *numberArray = [[VSBlockTestedObjectArray alloc] initWithTestBlock:^BOOL(id element) { return [element isKindOfClass:[NSNumber class]]; } FailBlock:^(id element) { NSLog(@"%@ can't be added, didn't pass the test. It is not an object of class NSNumber", element); }]; [stringArray addObject:@"test"]; [stringArray addObject:@"test1"]; [stringArray addObject:[NSNumber numberWithInt:9]]; [stringArray addObject:@"test2"]; [stringArray addObject:@"test3"]; [numberArray addObject:@"test"]; [numberArray addObject:@"test1"]; [numberArray addObject:[NSNumber numberWithInt:9]]; [numberArray addObject:@"test2"]; [numberArray addObject:@"test3"]; NSLog(@"%@", stringArray); NSLog(@"%@", numberArray); 

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

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

Поэтому, если вы хотите ввести типы / проверки в NSArray, вы можете подойти к нему, используя что-то вроде этого:

 template  class t_typed_NSMutableArray { public: t_typed_NSMutableArray() : d_array([NSMutableArray new]) {} ~t_typed_NSMutableArray() { [d_array release]; } /* ... */ T* operator[](const size_t& idx) { T* const obj([this->d_array objectAtIndex:idx]); assert([obj isKindOfClass:[T class]]); return obj; } void addObject(T* const obj) { assert([obj isKindOfClass:[T class]]); [this->d_array addObject:obj]; } private: NSMutableArray * const d_array; }; 

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

  t_typed_NSMutableArray array([self cards]); // < note this exact constructor is not defined Card * firstCard = array[0]; // << ok NSString * string = array[0]; // << warning 

то вы также получаете безопасность и перегрузку типов при передаче коллекции, поэтому вы не можете передать t_typed_NSArray как t_typed_NSArray .

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

Вы можете повторно реализовать вырезанную версию шаблона C ++ в Obj-C, поскольку Obj-C инкапсулирует все шаблоны C (и C ++ – это C-macros с некоторой улучшенной поддержкой компилятора / отладчика):

Это нужно сделать только один раз, используя один заголовочный файл. Кто-то сделал это за вас:

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

Вы получаете 100% -ный юридический код Obj-C, который выглядит следующим образом:

 NSArray anArray= ... CustomClass a = anArray[0]; // works perfectly, and Xcode autocomplete works too! 

Все это отлично работает в XCode, с автозаполнением и т. Д.

Interesting Posts

Не удалось загрузить файл или сборку «System.Web.Http 4.0.0 после обновления с 2012 по 2013 год»

Хранить FTP-папку в синхронизации с папкой Windows

Есть ли такая вещь, как карта памяти WORM (запись-один раз-много) или USB-накопитель?

В клон StackOverflow, какая связь должна иметь таблица комментариев в вопросах и ответах?

Как управлять исходным IP-адресом пакета ZeroMQ на компьютере с несколькими IP-адресами?

Почему C ++ не использует std :: nested_exception, чтобы позволить метать из деструктора?

Почему многие регионы чувствительны к регистру?

Открыть почтовые ссылки с gmail в Chrome 9

Не удается разрешить символ HttpGet, HttpClient, HttpResponce в Android Studio

Как изменить поисковую систему IE 10 в Windows RT

Как переместить профиль Chrome, а также открыть новые ссылки с перемещенным профилем?

Как получить доступ к файлам cookie в AngularJS?

выбрать событие выбора jquery select

Изменение имени хоста и запроса в терминале OS X

Разбор очень больших XML-документов (и немного больше) в java

Давайте будем гением компьютера.