Reputation: 768
I have this property:
@property (nonatomic) NSMutableArray <__kindof superclass*> *items;
I populate it with objects for a subclass (which should be ok due to __kindof). I retrieve the array like this:
NSMutableArray <__kindof subclass*> *items = holderObject.items;
But now I get this compiler warning:
Incompatible pointer types initializing 'NSMutableArray<subclass *> *' with an expression of type 'NSMutableArray<__kindof superclass *> * _Nullable'
Isn't this what __kindof is suposed to do for us? What am I doing wrong here?
UPDATE 2: This only happens for mutable arrays.
Update: here is some simple code that show the warning:
Create a new class GenericsError.h:
@import UIKit;
@interface GenericsError : NSObject
@property (nonatomic) NSMutableArray <__kindof UIViewController*> *generics;
@end
In any viewController just add:
GenericsError *error = [GenericsError new];
NSMutableArray <ViewController*>* controllers = error.generics;
(substitute ViewController for whatever your viewController is called). I'm not adding or creating anything, just getting the compiler warning for the generics-error.
Upvotes: 3
Views: 698
Reputation: 122449
The generic parameter of NSMutableArray
is invariant (it's declared @interface NSMutableArray<ObjectType>
and not @interface NSMutableArray<__covariant ObjectType>
or @interface NSMutableArray<__contravariant ObjectType>
). That means the type argument must match exactly for it to be compatible.
That means NSMutableArray<NSString *> *
cannot be assigned to NSMutableArray<NSObject *> *
, or vice versa, even though NSString *
can be assigned to NSObject *
. (On the other hand, the type parameter of NSArray
is covariant (it is declared NSArray<__covariant ObjectType>
), which means NSArray<NSString *> *
can be assigned to NSArray<NSObject *> *
.)
NSMutableArray<NSString *> *
cannot even be assigned to NSMutableArray<id> *
, or vice versa, even though NSString *
can be assigned to id
and id
can be assigned to NSString *
, in both directions. I guess the idea is that id
turns off static type checking, but only on uses of the actual type id
, and not for types that have id
as a type argument.
__kindof superclass *
is kind of a "limited" version of id
-- it turns off static type checking, but only when assigning to and from subtypes of superclass *
. For the same reason that NSMutableArray<id> *
cannot be assigned to or from NSMutableArray<someclass *> *
above, NSMutableArray<__kindof superclass *> *
also cannot be assigned to or from NSMutableArray<subclass *> *
.
Upvotes: 1
Reputation: 2733
You have an inheritance A -> B (where A is the subclass and B is the superclass), you declared a container to hold instances of A but you are trying to put instances of B inside the container. It's not guaranteed that all the instances of B are also instances of A.
Imagine to have another class C -> B (where C is a subclass of B, and B is the same superclass mentioned above). In this case C is __kindof B but it's not __kindof A, hence the warning.
Long story short: you need to use __kindof superclass when declaring your container, to suppress the warning.
Upvotes: -1