我一直在检查iOS 9作为开发人员的新功能,其中一些像StackView看起来很棒.
当我去UIStackView的头文件时,我看到了这个:
@property(nonatomic,readonly,copy) NSArray<__kindof UIView *> *arrangedSubviews;
Run Code Online (Sandbox Code Playgroud)
什么是NSArray*的__kindof.我们现在能够在NSArray*上指定类型吗?
小测试:
@interface DXTEST ()
@property (strong, nonatomic) NSMutableArray <__kindof NSString *> *strings;
@end
@implementation DXTEST
- ( instancetype ) init {
self = [super init];
if( self ) {
_strings = [NSMutableArray new];
[_strings addObject:@(1)]; <-- compiler warning wieeeeee
}
return self;
}
@end
Run Code Online (Sandbox Code Playgroud)
Art*_*mov 61
可悲的是,目前最高投票的答案有点不正确.
实际上,您可以将任何子类添加<T>到泛型集合中:
@interface CustomView : UIView @end
@implementation CustomView @end
NSMutableArray<UIView *> *views;
UIView *view = [UIView new];
CustomView *customView = [CustomView new];
[views addObject:view];
[views addObject:customView];//compiles and runs!
Run Code Online (Sandbox Code Playgroud)
但是,当您尝试检索对象时,它将被严格键入,<T>并且需要转换:
//Warning: incompatible pointer types initializing
//`CustomView *` with an expression of type `UIView * _Nullable`
CustomView *retrivedView = views.firstObject;
Run Code Online (Sandbox Code Playgroud)
但是,如果您要添加__kindof关键字,则返回的类型将更改为,kindof T并且不需要转换:
NSMutableArray<__kindof UIView *> *views;
<...>
CustomView *retrivedView = views.firstObject;
Run Code Online (Sandbox Code Playgroud)
TLDR:Objective-C中的泛型可以接受子类<T>,__kindof关键字指定返回值也可以是子类<T>.
Mic*_*lum 41
我们现在能够在NSArray*上指定类型吗?
是的,通过Objective-C的新轻量级泛型.在您提供的示例中,您有一个type属性NSArray,它将接受UIViews的元素.
现在,这可以指定如下(没有__kindof).
@property(nonatomic,readonly,copy) NSArray<UIView *> *arrangedSubviews;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,数组将接受其类是的对象UIView,但不接受任何子类的对象UIView.该__kindof声明将数组的泛型类型标记为可以接受UIView类的实例和任何子类的实例的类型UIView.
编辑:
我删除了原始答案的大部分,因为我错误地认为指定数组的类型会阻止您插入不正确类型的对象,而事实并非如此.(感谢Artem Abramov指出这一点.请参阅下面的答案以获取更多详情)
Objective-C的泛型似乎存在,在访问泛型集合的元素时为您提供类型信息.例如,请考虑下面的代码添加UIView和UIImageView到NSMutableArray<UIView *>.两个对象都插入到数组中而没有编译器或运行时的任何抱怨,但是当您尝试访问元素时,如果变量的类型不是数组的泛型类型,则编译器会警告您(UIView),即使它是其中一个UIView子类.
NSMutableArray<UIView *> *subviews = [[NSMutableArray alloc] init];
[subviews addObject:[[UIView alloc] init]]; // Works
[subviews addObject:[[UIImageView alloc] init]]; // Also works
UIView *sameView = subviews[0]; // Works
UIImageView *sameImageView = subviews[1]; // Incompatible pointer types initializing 'UIImageView *' with an expression of type 'UIView *'
NSLog(@"%@", NSStringFromClass([sameView class])); // UIView
NSLog(@"%@", NSStringFromClass([sameImageView class])); // UIImageView
Run Code Online (Sandbox Code Playgroud)
现在,这会产生编译时警告,但不会在运行时崩溃.这个和数组的泛型类型被标记为的相同示例之间的关键区别在于__kindof,如果您尝试访问其元素的某个元素,编译器将不会抱怨,并将结果存储在类型为UIView 或者其类型之一的变量中子类.
NSMutableArray<__kindof UIView *> *subviews = [[NSMutableArray alloc] init];
[subviews addObject:[[UIView alloc] init]]; // Works
[subviews addObject:[[UIImageView alloc] init]]; // Also works
UIView *sameView = subviews[0]; // No problem
UIImageView *sameImageView = subviews[1]; // No complaints now!
NSLog(@"%@", NSStringFromClass([sameView class])); // UIView
NSLog(@"%@", NSStringFromClass([sameImageView class])); // UIImageView
Run Code Online (Sandbox Code Playgroud)
iOS9在ObjC上引入了轻量级泛型.ObjC是一种非常动态的语言,而SWIFT更喜欢静态类型,为了最大化互操作性和类型检查现在在ObjC中你可以声明一个这样的数组:
NSArray<UIView *> *views;
Run Code Online (Sandbox Code Playgroud)
这意味着所有视图对象都是UIView对象的实例,想象UIView子视图属性它可以包含可以是不同类型的元素,UIViews和继承自的对象UIView,但编译器会抱怨,因为即使它们继承它们也是不同的类型.
这是__kindof发挥作用.就像是说数组包含类型的对象UIView.
就像仍然使用一种id类型的优势,但仅限于一种类.
| 归档时间: |
|
| 查看次数: |
9809 次 |
| 最近记录: |