I have read the article about some new features of objective-C in iOS. However, I cannot get what is the main difference between these two ways:
@property (strong, nonatomic, nonnull) NSArray<UIView *> *someViews;
and
@property (strong, nonatomic, nonnull) NSArray<__kindof UIView *> *someViews;
For me, they look pretty similar. What is the difference, and when I should use one over another?
It's all simple. In the first case you will need write:
UILabel* titleLabel = (typeof(titleLabel))someViews[0];
In the second you can just write:
UILabel* titleLabel = someViews[0];
You should choose which way you prefer: implicit or explicit type casting.
To see the full effect of the __kindof
I would recommend just putting it to use and taking a look at the different outcome:
NSMutableArray<UIView *> *views;
NSMutableArray<__kindof UIView *> *subviews;
views = [NSMutableArray new];
subviews = [NSMutableArray new];
UIView *someView = [UIView new];
[views addObject:someView];
[subviews addObject:someView];
UIButton *someSubview = [UIButton new];
[views addObject:someSubview];
[subviews addObject:someSubview];
So far for the insertion into the different generic arrays. Both compile and run just fine. No warnings, no crashes.
The interesting part however is reading from the arrays - keep in mind that in the first slot of both arrays is an actual UIView *
, in the second slot is a 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];
This will run fine, but give two compiler warnings for the marked lines:
Incompatible pointer types initializing 'UIButton *' with an expression of type 'UIView *'
The other two lines work as expected. Still of course no crash. But we have some problematic situation present: extButton01
contains a UIView *
but looks like a UIButton *
.
Therefore adding the following
NSLog(@"%@", extButton00.titleLabel);
NSLog(@"%@", extButton01.titleLabel);
NSLog(@"%@", extButton10.titleLabel);
NSLog(@"%@", extButton11.titleLabel);
crashes as expected on the first and second line. If we remove the entire views
array we will end up with warning-free but crashing code. And I do not like crashing but warning-free code. Of course warning-free does not guarantee no crashes but removing warnings for convenience sake is not a good idea IMHO.
Yes, that feature is neat for removing a cast. BUT it also removes the possibly helpful warning of mismatched types. If you are 100% sure that your object at index X is of type T then you could go with the subviews
approach of using __kindof
.
I, personally, would/will not use it yet - until I come across a really, really good use case which I fail to see yet.
You know how you can declare a variable like id foo
to indicate that foo a pointer to any kind of object, and that you can then send any message to foo
without the compiler complaining? kindof__ UIView* foo
is like that -- it lets you specify that foo
is some "kind of" view, but you can send any message to foo
that would be valid for any kind of view without needing to cast. For example:
UIView *bar = [[UIButton alloc] initWithFrame:CGRectZero];
[bar setTarget:nil];
In this case, the compiler will complain about the second line because -setTarget:
isn't a method in UIView
. If you want to get that to compile, you have to cast like:
[(UIButton*)bar setTarget:nil];
__kindof
lets you avoid that:
__kindof UIView *foo = [[UIButton alloc] initWithFrame:CGRectZero];
[foo setTarget:nil];
Here you're telling the compiler that foo
could be any kind of view, which makes it relax a little and lets you call -setTarget:
without having to cast it to UIButton*
. You could just declare foo
as id foo
and get a similar effect, but specifying that foo
is some kind of view gives the compiler more information to work with. Specifically it makes it possible to write Objective-C code that plays nicely with Swift, which is more strongly typed than Objective-C.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With