__kindof之间的区别与不在Objective-C中使用它

时间:2015-11-19 08:03:28

标签: ios objective-c nsarray

我已经阅读了article关于iOS中Objective-C的一些新功能。但是,我无法得到这两种方式之间的主要区别:

@property (strong, nonatomic, nonnull) NSArray<UIView *> *someViews;

@property (strong, nonatomic, nonnull) NSArray<__kindof UIView *> *someViews;

对我来说,它们看起来非常相似。有什么区别,什么时候我应该使用另一个?

3 个答案:

答案 0 :(得分:12)

要查看__kindof的完整效果,我建议您使用它并查看不同的结果:

NSMutableArray<UIView *> *views;
NSMutableArray<__kindof UIView *> *subviews;

views = [NSMutableArray new];
subviews = [NSMutableArray new];

UIView *someView = [UIView new];

[subviews addObject:someView];
[views addObject:someView];

UIButton *someSubview = [UIButton new];

[subviews addObject:someSubview];
[views addObject:someSubview];

到目前为止,插入到不同的通用数组中。编译和运行都很好。没有警告,没有崩溃。

然而有趣的部分是从数组中读取 - 请记住,在两个数组的第一个插槽中是实际的UIView*,在第二个插槽中是UIButton*

UIView *extView00 = views[0];
UIView *extView01 = subviews[0];
UIView *extView10 = views[1];
UIView *extView11 = subviews[1];

UIButton *extButton00 = views[0]; <-- warning
UIButton *extButton01 = subviews[0];
UIButton *extButton10 = views[1]; <-- warning
UIButton *extButton11 = subviews[1];

这样运行正常,但为标记的行提供两个编译器警告:

  

使用“UIView *”类型的表达式初始化“UIButton *”的指针类型不兼容

其他两行按预期工作。当然还没有崩溃。但我们遇到了一些问题:extButton01包含UIView*,但看起来像UIButton*

因此添加以下内容

NSLog(@"%@", extButton00.titleLabel);
NSLog(@"%@", extButton01.titleLabel);
NSLog(@"%@", extButton10.titleLabel);
NSLog(@"%@", extButton11.titleLabel);

在第一行和第二行按预期崩溃。如果我们删除整个视图数组,我们最终将获得无警告但崩溃的代码。而且我不喜欢崩溃但是没有警告的代码。当然,无警告并不能保证不会发生崩溃,但为了方便起见而删除警告并不是一个好主意恕我直言。

结论

是的,该功能可以很好地删除演员阵容。 但是它还会删除不匹配类型的可能有用的警告。如果您100%确定索引X处的对象是T类型,那么您可以使用subviews方法使用__kindof

我个人将会/现在不会使用它 - 直到我遇到一个我看不到的非常好的用例。

答案 1 :(得分:4)

一切都很简单。 在第一种情况下,您需要写:

UILabel* titleLabel = (typeof(titleLabel))someViews[0];

在第二个你可以写:

UILabel* titleLabel = someViews[0];

您应该选择您喜欢的方式:隐式或显式类型转换。

答案 2 :(得分:3)

您知道如何声明像 $str = 'LKR56.90'; $inoice_subTot = trim($str,"LKR"); 这样的变量来指示foo指向任何类型对象的指针,然后您可以在没有编译器抱怨的情况下将任何消息发送到id foo吗? foo就是这样 - 它允许您指定kindof__ UIView* foo是某种“类型”视图,但您可以向foo发送任何对任何类型的视图都有效的消息需要施放。例如:

foo

在这种情况下,编译器会抱怨第二行,因为UIView *bar = [[UIButton alloc] initWithFrame:CGRectZero]; [bar setTarget:nil]; 不是-setTarget:中的方法。如果你想要编译,你必须像:

UIView

[(UIButton*)bar setTarget:nil]; 可以避免这种情况:

__kindof

在这里,您告诉编译器__kindof UIView *foo = [[UIButton alloc] initWithFrame:CGRectZero]; [foo setTarget:nil]; 可以是任何类型的视图,这使得它放松一点,让您调用foo而无需将其转换为-setTarget:。您可以将UIButton*声明为foo并获得类似的效果,但指定id foo是某种视图会为编译器提供更多信息。特别是它可以编写与Swift很好地结合的Objective-C代码,它比Objective-C更强类型。