我知道我可以使用__kindof
关键字来使用Objective-C的轻量级泛型,例如
NSArray<__kindof BaseClass*> *myArray;
这将删除将数组中的任何对象分配给派生类的任何警告。
但是,我BaseClass
代替BaseProtocol
,而不是BaseProtocol
。无论基类如何,我所讨论的所有类都将符合BaseProtocol
。我想使用轻量级泛型来指示&#34;我的数组由符合List<IMyInterface>
的元素组成,但它们可以是任何类&#34;。
例如在C#中,我可以说:IMyInterface
这意味着该列表包含实现NSArray<__kindof id<MyProtocol>> //compiles, but as the generic argument is "id", it accepts any object, including invalid ones
接口的元素(我知道C#具有强大的泛型,而Objective-C只有轻量级泛型这并不妨碍编译,但你明白了。
有没有办法在Objective-C上实现这个功能?
E.g。我想写
NSArray<id<__kindof MyProtocol>> //doesn't compile
或
@protocol MyProtocol
@end
@interface MyClass : NSObject<MyProtocol>
@end
@implementation MyClass
@end
@interface AnotherClass : NSObject
@end
@implementation AnotherClass
@end
NSMutableArray<__kindof id<MyProtocol>> *myArray;
void test(){
MyClass *myClassInstance = [[MyClass alloc] init];
AnotherClass *anotherClassInstance = [[AnotherClass alloc] init];
myArray = @[].mutableCopy;
[myArray addObject:myClassInstance];
[myArray addObject:anotherClassInstance]; //i get warning. good.
MyClass *returnedInstance = myArray[0];
AnotherClass *anotherInstance = myArray[1]; //why don't I get a warning here?
}
这可能吗?
更新:
这是一个完整的自包含代码:
Composite Template
答案 0 :(得分:4)
这种语法是正确的:
NSArray <__kindof id <MyProtocol>> *array = ...
您也可以省略__kindof
,并且仍然享受轻量级的泛型。即使没有该关键字,它仍会警告您添加错误类型的对象。如果要从对象中拉出一个对象并将其分配给没有强制转换的子类型,则使用__kindof
,否则不需要__kindof:
NSArray <id <MyProtocol>> *array = ...
如果将特定类型的对象添加到数组中,这两种模式都会发出警告,但该类型不符合MyProtocol
。
如果您尝试单独添加id
类型的对象,那么这不会警告您。因此,请避免在代码中使用不合格的id
类型,并且您将享受轻量级泛型。
如果您仍未看到警告,请确保已启用-Wobjc-literal-conversion
警告。所以,回到第一个项目的构建设置并搜索“literal”,你会看到设置(称为“Implicit Objective-C Literal Conversions”)。
考虑这个例子:
@protocol MyProtocol
@end
@interface Foo: NSObject <MyProtocol>
@end
@interface Bar: Foo
@end
@interface Baz: NSObject
@end
然后考虑:
Foo *foo = [[Foo alloc] init];
Bar *bar = [[Bar alloc] init];
Baz *baz = [[Baz alloc] init];
id qux = [[Baz alloc] init];
NSArray <id <MyProtocol>> *array1;
array1 = @[foo, bar, baz, qux]; // warning: object of type 'Baz *' is not compatible with array element type 'Foo *'
注意,这会警告我们baz
,而不是qux
。所以要小心使用id
类型。
id <MyProtocol> object1 = array1[0]; // no warning, great
所以,这是使用协议作为轻量级通用,它按预期工作。
您添加__kindof
的唯一原因是您要避免此警告:
Foo *foo1 = array1[0]; // warning: initializing 'Foo *__strong' with an expression of incompatible type 'id<MyProtocol> _Nullable'
在这种情况下,您使用__kindof
:
NSArray <__kindof id <MyProtocol>> *array2;
array2 = @[foo, bar, baz]; // again, warning: object of type 'Baz *' is not compatible with array element type 'Foo *'
id <MyProtocol> object2 = array2[0]; // no warning, great
Foo *foo2 = array2[0]; // no warning, great