我已经阅读了article关于iOS中Objective-C的一些新功能。但是,我无法得到这两种方式之间的主要区别:
@property (strong, nonatomic, nonnull) NSArray<UIView *> *someViews;
和
@property (strong, nonatomic, nonnull) NSArray<__kindof UIView *> *someViews;
对我来说,它们看起来非常相似。有什么区别,什么时候我应该使用另一个?
答案 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更强类型。