代码之家  ›  专栏  ›  技术社区  ›  Can Poyrazoğlu

我可以在Objective-C中使用\uu kindof协议吗?

  •  4
  • Can Poyrazoğlu  · 技术社区  · 7 年前

    我知道我可以使用Objective-C的轻量级泛型 __kindof 关键字,例如。

    NSArray<__kindof BaseClass*> *myArray;
    

    这将删除将数组中的任何对象指定给派生类的任何警告。

    但是 BaseClass ,我有 BaseProtocol ,例如,我的所有相关课程都将符合 基本协议 ,而不考虑其基类。我想使用轻量级泛型来指示“我的数组由符合 基本协议 ,但它们可以是任何类”。

    例如,在C#中,我可以说: List<IMyInterface> 这意味着该列表由实现 IMyInterface 接口(我知道C#有强大的泛型,而Objective-C只有轻量级泛型,不会阻止编译,但你明白了)。

    有没有办法在Objective-C上实现此功能?

    E、 g.我想写

    NSArray<__kindof id<MyProtocol>> //compiles, but as the generic argument is "id", it accepts any object, including invalid ones
    

    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?
    }
    
    1 回复  |  直到 7 年前
        1
  •  5
  •   Rob Md Fahim Faez Abir    7 年前

    此语法正确:

    NSArray <__kindof id <MyProtocol>> *array = ...
    

    也可以省略 __kindof ,并且仍然喜欢轻量级泛型。即使没有该关键字,它仍然会警告您添加错误类型的对象。这个 __有点 如果要将对象从该数组中拉出并将其指定给不带强制转换的子类型,则使用,否则不需要\uu kindof:

    NSArray <id <MyProtocol>> *array = ...
    

    如果将特定类型的对象添加到数组中,但该类型不符合 MyProtocol

    这不会警告您的是,如果您尝试添加类型为的对象 id 它本身。因此,避免使用不合格的 id号 在代码中键入,您将享受轻量级泛型。

    如果仍然没有看到警告,请确保已看到 -Wobjc-literal-conversion 警告已打开。因此,返回第一个项目的构建设置并搜索“literal”,您将看到该设置(称为“隐式Objective-C literal转换”)。


    考虑以下示例:

    @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
    

    因此,这就是将该协议作为轻量级泛型使用,并按预期工作。

    你添加的唯一原因 __有点 如果要避免此警告:

    Foo *foo1 = array1[0];                    // warning: initializing 'Foo *__strong' with an expression of incompatible type 'id<MyProtocol> _Nullable'
    

    在这种情况下,您可以使用 __有点 :

    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
    
    推荐文章