【问题标题】:How to properly subclass a delegate property in Objective-C?如何在 Objective-C 中正确子类化委托属性?
【发布时间】:2012-03-19 04:27:19
【问题描述】:

在对类进行子类化时,我还想对父类的委托进行子类化,因为子类现在具有附加功能。这样做的最佳方法是什么?如果我只是在子类中声明另一个具有相同名称的委托属性,我会收到警告“属性类型 'id' 与继承自 'ParentClass' 的类型 'id' 不兼容

【问题讨论】:

    标签: objective-c inheritance


    【解决方案1】:

    鉴于这个产生警告的例子:

    // Class A
    @protocol ClassADelegete;
    
    @interface ClassA : NSObject
    @property (nonatomic, weak) id<ClassADelegete> delegate;
    @end
    
    @protocol ClassADelegete <NSObject>
    - (void)classADidSomethingInteresting:(ClassA *)classA;
    @end
    
    // Class B
    @protocol ClassBDelegete;
    
    @interface ClassB : ClassA
    @property (nonatomic, weak) id<ClassBDelegete> delegate; // Warning here
    @end
    
    @protocol ClassBDelegete <ClassADelegete>
    - (void)classBDidSomethingElse:(ClassB *)classB;
    @end
    

    消除警告的两种解决方案是。

    1) 在子类中,将协议定义放在类定义之前。这就是UITableViewDelegate in UITableView.h 所做的:

    // Class B
    @class ClassB;
    
    @protocol ClassBDelegete <ClassADelegete>
    - (void)classBDidSomethingElse:(ClassB *)classB;
    @end
    
    @interface ClassB : ClassA
    @property (nonatomic, weak) id<ClassBDelegete> delegate;
    @end
    

    2) 在子类中,在新协议旁边添加原始协议:

    // Class B
    @protocol ClassBDelegete;
    
    @interface ClassB : ClassA
    @property (nonatomic, weak) id<ClassADelegete, ClassBDelegete> delegate;
    @end
    
    @protocol ClassBDelegete <ClassADelegete>
    - (void)classBDidSomethingElse:(ClassB *)classB;
    @end
    

    我假设 (1) 像 Apple 那样工作,选项 (2) 删除了警告,但我还没有编译和运行任何以这种方式设置的东西。

    【讨论】:

    • 这可能有点晚了,但是同样的例子呢,但只有 ClassADelegete 和 ClassBDelegete 在 Swift 中,而 ClassA 和 ClassB 仍然在 Objective C 中?在这种情况下,我无法摆脱警告。
    【解决方案2】:

    NSTableViewNSOutlineView 为例。

    NSOutlineView 是 NSTableView 的子类,并为其dataSourcedelegate 定义了自己的协议。

    NSTableView 这样声明它的委托:

    - (void)setDelegate:(id <NSTableViewDelegate>)delegate;
    - (id <NSTableViewDelegate>)delegate;
    

    NSOutlineView:

    - (void)setDelegate:(id <NSOutlineViewDelegate>)anObject;
    - (id <NSOutlineViewDelegate>)delegate;
    

    显然编译器对裸方法声明比对属性声明更宽松。

    与 NSTable/OutlineView 不同,您可能希望使子类的协议继承自基类的协议,例如

     @protocol SpecializedProtocol <BaseProtocol>
    

    ...这可能取决于情况。

    【讨论】:

    • 我选择了后一种路线(在对主类进行子类化后对委托协议进行子类化),但无法在不触发编译器错误的情况下声明另一个委托属性。你提到的方法声明是让编译器满意的唯一方法吗?
    • 我不知道有其他方法可以做到这一点。
    猜你喜欢
    • 1970-01-01
    • 2011-02-13
    • 2011-03-30
    • 2023-03-05
    • 2012-07-17
    • 2010-09-10
    • 2010-11-05
    • 1970-01-01
    • 2017-12-09
    相关资源
    最近更新 更多