Objective-C中有强types的集合吗?

我是Mac / iPhone编程和Objective-C的新手。 在C#和Java中,我们有“generics”,集合类的成员只能是声明的types。 例如,在C#

Dictionary<int, MyCustomObject>

只能包含键types为MyCustomObject的整数和值。 Objective-C中是否存在类似的机制?

在Xcode 7中,苹果已经向Objective-C引入了“轻量级generics”(Lightweight Generics)。 在Objective-C中,如果types不匹配,它们将生成编译器警告。

 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' 

除了这些基础集合类,Objective-C轻量级generics被Swift忽略。 任何其他使用轻量级generics的types都会被导入到Swift中,就好像它们没有被参数化一样。

与Objective-C API交互

这个答案已经过时了,但仍然具有历史价值。 从Xcode 7开始,Connor从15年6月8日的答案更准确。


不,在Objective-C中没有generics,除非你想在自己的自定义集合类中使用C ++模板(我强烈build议不要这样做)。

Objective-C具有dynamictypes化function,这意味着运行时并不关心对象的types,因为所有对象都可以接收消息。 当你添加一个对象到一个内置的集合中时,他们只是被视为typesid 。 但是不要担心,只要像往常一样发送消息给这些对象。 它会正常工作(除非收集中的一个或多个对象不响应您发送的消息)

在Java和C#等语言中需要generics,因为它们是强大的静态types语言。 完全不同于Objective-C的dynamic打字function。

不,但为了使它更清晰,你可以用你想要存储的对象的types来评论它,当你需要在Java 1.4中编写一些东西时,我已经看到了这样做了几次)例如:

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

要么

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

Objective-C中没有generics。

从文档

数组是有序的对象集合。 Cocoa提供了几个数组类,NSArray,NSMutableArray(NSArray的一个子类)和NSPointerArray。

苹果在XCode 7中为ObjC添加了仿制药:

 @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

这是在Xcode 7发布 (最后!)

请注意,在Objective C代码中,这只是编译时检查; 只会将错误的types放入集合或分配给某个types的属性,不会有运行时错误。

宣布:

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

使用:

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

小心这些*

通用NSArrays可以通过NSArray的子类化,并重新定义所有提供更具限制性的方法来实现。 例如,

 - (id)objectAtIndex:(NSUInteger)index 

将不得不被重新定义

 @interface NSStringArray : NSArray 

 - (NSString *)objectAtIndex:(NSUInteger)index 

NSArray只包含NSString。

创build的子类可以作为一个插件replace,并带来许多有用的function:编译器警告,属性访问,更好的代码创build和Xcode中的完成。 所有这些都是编译时的function,不需要重新定义实际的实现 – NSArray的方法仍然可以使用。

这可以自动化,并将其归结为只有两个语句,这使它接近支持generics的语言。 我已经使用WMGenericCollection创build了一个自动化,模板以C预处理器macros的forms提供。

导入包含macros的头文件后,可以用两个语句创build一个通用NSArray:一个用于接口,另一个用于实现。 你只需要提供你想存储的数据types和你的子类的名字。 WMGenericCollection为NSArrayNSDictionaryNSSet以及它们的可变对象提供了这样的模板。

一个例子: List<int>可以通过一个名为NumberArray的自定义类来实现,该类使用以下语句创build:

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

一旦你创build了NumberArray ,你可以在你的项目中的任何地方使用它。 它缺less<int>的语法,但是您可以select自己的命名scheme,将它们标记为模板类。

看一眼:

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

这似乎是一种穷人的generics,通过重新使用协议检查机制。

现在梦想成真了 – 从今天开始,Objective-C就有generics(感谢WWDC)。 这不是一个笑话 – 在Swift的官方网页上:

新的语法function使您可以编写更具performance力的代码,同时提高整个语言的一致性。 SDK使用了新的Objective-Cfunction,如generics和可空性注释,使Swift代码更加清洁和安全。 这里只是Swift 2.0增强的一个示例。

和certificate这一点的图像: Objective-C泛型

只想在这里跳。 我在这里写了一篇关于generics的博客文章。

我想贡献的是generics可以被添加到任何类 ,而不仅仅是苹果指出的集合类。

我已经成功添加到各种类,因为他们的工作完全一样苹果的collections。 即。 编译时间检查,代码完成,允许删除剧组等。

请享用。

由Apple和GNUStep框架提供的集合类是半通用的,因为它们假设它们是给定的对象,有些是可sorting的,有些是对某些消息作出响应的。 对于像浮点数,整数等原始数据,所有的C数组结构都是完整的,可以使用,并且有一些特殊的包装对象用于一般的集合类(例如NSNumber)。 另外,一个Collection类可以被分类(或者通过类别特别修改)来接受任何types的对象,但是你必须自己编写所有的types处理代码。 消息可以发送给任何对象,但是如果对象不适合,应该返回null,或者消息应该被转发给适当的对象。 应该在编译时捕获真正的types错误,而不是在运行时捕获。 在运行时应该处理或忽略它们。 最后,Objc提供了运行时reflectionfunction来处理棘手的情况,消息响应,特定types和服务可以在发送消息或放入不适当的集合之前在对象上进行检查。 请注意,不同的库和框架采用不同的约定,以便在发送消息时对象的行为如何,因此RTFM没有代码响应。 除了玩具程序和debugging版本之外,大多数程序不应该崩溃,除非它们真的搞砸了,试图将不良数据写入内存或磁盘,执行非法操作(例如,除以零,但也可以捕获),或者访问禁止系统资源。 Objective-C的dynamic和运行时间允许事情优雅地失败,并且应该被内置到你的代码中。 (提示)如果你的函数中的generics有问题,请尝试一些特殊性。 用特定的types编写函数,让运行时select适当的成员函数(这就是为什么称为select器!)。

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