iOS __kindof NSArray? iOS __kindof NSArray? ios ios

iOS __kindof NSArray?


Sadly the currently top voted answers are a bit incorrect.

You actually can add any subclass of <T> to a generic collection:

@interface CustomView : UIView @end@implementation CustomView @endNSMutableArray<UIView *> *views;UIView *view = [UIView new];CustomView *customView = [CustomView new];[views addObject:view];[views addObject:customView];//compiles and runs!

But when you'll try to retrieve the object, it will be strictly typed as <T> and will require casting:

//Warning: incompatible pointer types initializing //`CustomView *` with an expression of type `UIView * _Nullable`CustomView *retrivedView = views.firstObject;

But if you'll add __kindof keyword the returned type will be changed to kindof T and no casting will be required:

NSMutableArray<__kindof UIView *> *views;<...>CustomView *retrivedView = views.firstObject;

TLDR: Generics in Objective-C can accept subclasses of <T>, __kindof keyword specifies that return value can also be subclass of <T>.


Are we able to specify a type on a NSArray * now?

Yes, through Objective-C's new lightweight generics. In the example you provided, you have a property of type NSArray, which will accept elements that are UIViews.

Now, this can be specified as follows (without __kindof).

@property(nonatomic,readonly,copy) NSArray<UIView *> *arrangedSubviews;

And in this case, the array will accept objects whose class is UIView, but not any objects which are subclasses of UIView. The __kindof declaration marks the array's generic type as one which can accept both instances of the UIView class, and instances of any of UIView's subclasses.

Edit:

I've removed the bulk of my original answer since I mistakenly thought specifying the type of the array would prevent you from inserting objects of an incorrect type, and this is not the case. (Thanks to Artem Abramov for pointing this out. Please see his answer below for additional details)

Objective-C's generics seem to exist to give you type information when accessing the elements of a generic collection. For example, consider the following code which adds a UIView and a UIImageView to NSMutableArray<UIView *>. Both objects are inserted into the array without any complaints by the compilers or the runtime, but when you try to access the elements, you're warned by the compiler if the type of your variable is anything other than the generic type of the array (UIView), even if it's one of UIView's subclasses.

NSMutableArray<UIView *> *subviews = [[NSMutableArray alloc] init];[subviews addObject:[[UIView alloc] init]]; // Works[subviews addObject:[[UIImageView alloc] init]]; // Also worksUIView *sameView = subviews[0]; // WorksUIImageView *sameImageView = subviews[1]; // Incompatible pointer types initializing 'UIImageView *' with an expression of type 'UIView *'NSLog(@"%@", NSStringFromClass([sameView class])); // UIViewNSLog(@"%@", NSStringFromClass([sameImageView class])); // UIImageView

Now, this produces a compile time warning, but does not crash at runtime. The key difference between this and the same example where the array's generic type is marked as __kindof, is that the compiler won't complain if you try to access ones of its elements, and store the result in a variable who's type is UIView or one of its subclasses.

NSMutableArray<__kindof UIView *> *subviews = [[NSMutableArray alloc] init];[subviews addObject:[[UIView alloc] init]]; // Works[subviews addObject:[[UIImageView alloc] init]]; // Also worksUIView *sameView = subviews[0]; // No problemUIImageView *sameImageView = subviews[1]; // No complaints now!NSLog(@"%@", NSStringFromClass([sameView class])); // UIViewNSLog(@"%@", NSStringFromClass([sameImageView class])); // UIImageView


iOS9 introduced lightweight generics on ObjC. ObjC is a really dynamic language while SWIFT prefer static types, to maximize interoperability and type checking now in ObjC you can declare an array like that:

NSArray<UIView *> *views;

That means that all the views object are instances of UIView objects, imagine the UIView subviews property it can contains elements that can be of different types, UIViews and objects that inherits from UIView, but the compiler will complain because even if they inherits they are different types.
That is were __kindof come into play. Is like to say that the array contains objects that are kind of type UIView.
Is like still using the advantage of an id type but restricted to a kind of class.