2015年更新
这个答案最初是在2011年初写的,然后开始:
我们真正想要的是参数多态性,因此您可以声明NSMutableArray<NSString>
:但可惜的是,这种方式不可用。
在2015年,Apple显然通过在Objective-C中引入“轻量级泛型”来改变了这一点,现在您可以声明:
NSMutableArray<NSString *> *onlyStrings = [NSMutableArray new];
但是,一切都不尽如人意,请注意“轻量级” ...然后注意,上述声明的初始化部分不包含任何通用符号。尽管Apple引入了参数化集合,并在上述数组中直接添加了非字符串onlyStrings
,例如:
[onlyStrings addObject:@666];
将显示非法警告,类型安全性几乎没有皮肤深。考虑以下方法:
- (void) push:(id)obj onto:(NSMutableArray *)array
{
[array addObject:obj];
}
和同一类的另一个方法中的代码片段:
NSMutableArray<NSString *> *oops = [NSMutableArray new];
[self push:@"asda" onto:oops];
[self push:@42 onto:oops];
苹果公司实际上实现的是一个提示系统,以协助与Swift进行自动互操作,它确实具有类型安全的泛型。但是,在Objective-C方面,尽管编译器提供了一些额外的提示,但系统是“轻量级的”,类型完整性最终仍归程序员所有(这与Objective-C的方式一样)。
那么您应该使用哪个呢?新的轻量级/伪泛型,还是为代码设计自己的模式?确实没有正确的答案,找出在您的方案中有意义的方法并使用它。
例如:如果您打算与Swift互操作,则应使用轻量级泛型!但是,如果集合的类型完整性在您的场景中很重要,那么您可以将轻量级泛型与您在Objective-C端的代码结合起来,从而在Swift方面实现Swift的类型完整性。
2011年答案的其余部分
作为另一个选择,这里是NSMutableArray的快速通用子类,您可以使用单态数组中所需的对象类型来初始化该子类。此选项不会为您提供静态类型检查(与在Obj-C中获得的一样多),您会在插入错误类型时获得运行时异常,就像您获得索引超出范围时的运行时异常等一样。
这没有经过彻底测试,并且假定有关覆盖NSMutableArray的文档是正确的...
@interface MonomorphicArray : NSMutableArray
{
Class elementClass;
NSMutableArray *realArray;
}
- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems;
- (id) initWithClass:(Class)element;
@end
并执行:
@implementation MonomorphicArray
- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems
{
elementClass = element;
realArray = [NSMutableArray arrayWithCapacity:numItems];
return self;
}
- (id) initWithClass:(Class)element
{
elementClass = element;
realArray = [NSMutableArray new];
return self;
}
- (void) insertObject:(id)anObject atIndex:(NSUInteger)index
{
if ([anObject isKindOfClass:elementClass])
{
[realArray insertObject:anObject atIndex:index];
}
else
{
NSException* myException = [NSException
exceptionWithName:@"InvalidAddObject"
reason:@"Added object has wrong type"
userInfo:nil];
@throw myException;
}
}
- (void) removeObjectAtIndex:(NSUInteger)index
{
[realArray removeObjectAtIndex:index];
}
- (NSUInteger) count
{
return [realArray count];
}
- (id) objectAtIndex:(NSUInteger)index
{
return [realArray objectAtIndex:index];
}
static id NotSupported()
{
NSException* myException = [NSException
exceptionWithName:@"InvalidInitializer"
reason:@"Only initWithClass: and initWithClass:andCapacity: supported"
userInfo:nil];
@throw myException;
}
- (id)initWithArray:(NSArray *)anArray { return NotSupported(); }
- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { return NotSupported(); }
- (id)initWithContentsOfFile:(NSString *)aPath { return NotSupported(); }
- (id)initWithContentsOfURL:(NSURL *)aURL { return NotSupported(); }
- (id)initWithObjects:(id)firstObj, ... { return NotSupported(); }
- (id)initWithObjects:(const id *)objects count:(NSUInteger)count { return NotSupported(); }
@end
用于:
MonomorphicArray *monoString = [[MonomorphicArray alloc] initWithClass:[NSString class] andCapacity:3];
[monoString addObject:@"A string"];
[monoString addObject:[NSNumber numberWithInt:42]];
[monoString addObject:@"Another string"];