我是Mac / iPhone编程和Objective-C的新手。在C#和Java中,我们有“泛型”集合类,其成员只能是声明的类型。例如,在C#中
Dictionary<int, MyCustomObject>
只能包含整数键和MyCustomObject类型的值。在Objective-C中是否存在类似的机制?
我是Mac / iPhone编程和Objective-C的新手。在C#和Java中,我们有“泛型”集合类,其成员只能是声明的类型。例如,在C#中
Dictionary<int, MyCustomObject>
只能包含整数键和MyCustomObject类型的值。在Objective-C中是否存在类似的机制?
Answers:
苹果在Xcode 7中向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集合类之外,Swift还会忽略Objective-C轻量级泛型。任何其他使用轻量级泛型的类型都将被导入到Swift中,就像它们是未参数化的一样。
MyClass <Foo: id<Bar>>
,您的Swift代码将假定值是约束的类型,这使您可以使用一些东西。但是,的特殊子类MyClass
将忽略其特殊类型(实际上与泛型相同MyClass
)。参见github.com/bgerstle/LightweightGenericsExample
这个答案已经过时了,但仍然具有历史价值。从Xcode 7开始,Connor从15年6月8日开始的回答更加准确。
不,除非您要在自己的自定义集合类中使用C ++模板(否则我强烈建议),那么Objective-C中没有泛型。
Objective-C具有动态类型化功能,这意味着运行时不关心对象的类型,因为所有对象都可以接收消息。当您将对象添加到内置集合中时,它们将被视为type对待id
。但是不用担心,只需像平常一样向这些对象发送消息即可。它将正常工作(除非集合中的一个或多个对象不响应您发送的消息)。
Java和C#等语言都需要泛型,因为它们是强大的静态类型的语言。完全不同于Objective-C的动态打字功能。
在Objective-C中没有泛型。
数组是对象的有序集合。Cocoa提供了几个数组类:NSArray,NSMutableArray(NSArray的子类)和NSPointerArray。
Apple已在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代码中,这只是一个编译时检查。仅将错误的类型放入集合或分配给typed属性,就不会有运行时错误。
宣布:
@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end
用:
FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];
小心那些*
。
通用NSArray可以通过子类实现NSArray
,并使用限制性更强的方法重新定义所有提供的方法。例如,
- (id)objectAtIndex:(NSUInteger)index
将不得不在
@interface NSStringArray : NSArray
如
- (NSString *)objectAtIndex:(NSUInteger)index
NSArray仅包含NSStrings。
创建的子类可以用作嵌入式替换,并带来许多有用的功能:编译器警告,属性访问,更好的代码创建和Xcode中的-completion。所有这些都是编译时功能,无需重新定义实际的实现-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>
,但是您可以选择自己的命名方案以将它们标记为类作为模板。
Apple和GNUStep框架提供的Collections类是半通用的,因为它们假定给了它们对象,有些是可排序的,有些是响应某些消息的。对于浮点数,整数等原语,所有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];