【问题标题】:iOS Subclassing and compulsory methodsiOS 子类化和强制方法
【发布时间】:2012-10-26 10:12:29
【问题描述】:

我有一个基础视图控制器,它是许多其他视图控制器的子类。有没有办法强制执行某些必须在子类中重写的方法?

为了安全,最重要的是。

干杯

【问题讨论】:

标签: objective-c ios inheritance methods enforcement


【解决方案1】:

在 Xcode(使用 clang 等)中,我喜欢使用 __attribute__((unavailable(...))) 来标记抽象类,以便在尝试使用它时会收到错误/警告。

它提供了一些防止意外使用该方法的保护。

示例

在基类@interface 中标记“抽象”方法:

- (void)myAbstractMethod:(id)param1 __attribute__((unavailable("You should always override this")));

更进一步,我创建了一个宏:

#define UnavailableMacro(msg) __attribute__((unavailable(msg)))

这让你可以这样做:

- (void)myAbstractMethod:(id)param1 UnavailableMacro("You should always override this");

就像我说的,这不是真正的编译器保护,但它与您使用不支持抽象方法的语言一样好。

【讨论】:

  • 如果您想要某种限制但又不想花太多时间重新设计课程,那么这是一个不错的解决方案。
  • 如果你得到参数 unavailable attribute is not a string literal 使用这个:__attribute__((unavailable("You should always override this")));
【解决方案2】:

在其他语言中,这是使用抽象类和方法完成的。在 Objective-C 中没有这样的东西。

你能得到的最接近的方法是在超类中引发异常,因此子类被“强制”覆盖它们。

[NSException raise:NSInternalInconsistencyException format:@"Subclasses must override %@", NSStringFromSelector(_cmd)];

【讨论】:

  • 同意,值得一提的是,精心设计的“抽象类替代方案”不应该要求在子类中实现导致异常的方法,而是应该在文档或任何类型的所需初始化器中明确提及可以执行检查修改NSError 参数。
  • 你可能想要 NSAssert(NO,@"This method need to be implemented) 而不是总是引发 NSException。默认情况下,NSAssert 对发布目标是禁用的。所以在不太可能的情况下,未实现的方法会滑倒通过投入生产它不会使应用程序崩溃。您还可以考虑使用带有@protocol的必需方法。
【解决方案3】:

受到 rjstelling 的启发,我以更令人满意的方式解决了这个问题:

在你的前缀中,定义:

#define abstract __attribute__((unavailable("abstract method")))

然后你可以添加抽象方法如下:

- (void) getDataIdentifier abstract;

尝试调用此方法将导致编译器语义问题/错误(Xcode 5.1):

'getDataIdentifier' is unavailable: abstract method

更新: 调用该方法似乎不起作用(至少不是从类层次结构中)。如果我设法解决这个问题,我会回来更新。

【讨论】:

    【解决方案4】:

    您可以通过使用 LLVM 功能在编译时要求子类实现属性(方法见下文),如下所示:

    NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION
    @protocol Protocol
    @property (readonly) id theWorstOfTimes; // expected-note {{property declared here}} 
    @end
    
    // In this example, ClassA adopts the protocol.
    @interface ClassA : NSObject <Protocol>
    @property (readonly) id theWorstOfTimes;
    @end
    
    @implementation ClassA
    - (id)theWorstOfTimes{
        return nil; // default implementation does nothing
    }
    @end
    
    // This class subclasses ClassA (which also adopts 'Protocol').
    @interface ClassB : ClassA <Protocol>
    @end
    
    @implementation ClassB // expected-warning {{property 'theWorstOfTimes' requires method 'theWorstOfTimes' to be defined - use @synthesize, @dynamic or provide a method implementation in this class implementation}} 
    @end
    

    正如您所见,当 ClassB 重新实现协议时,它会显示 expected-warning 缺少属性方法。 NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION 只是 __attribute__((objc_protocol_requires_explicit_implementation)) 的宏,此代码示例是从该功能 here 的测试工具修改而来的。

    这曾经也适用于方法,但在 2014 年通过 misunderstanding in what it is for 引入了一个错误,现在它只适用于属性,我已通过电子邮件向作者发送电子邮件让他们知道,因此希望它恢复到原来的样子。要测试错误,您可以向协议添加一个方法,您将看到 ClassB 中没有警告。希望您可以将一些方法更改为只读属性,以至少从中获得一些用处。

    这是NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION 的一些文档: ImplementingAccessibilityforCustomControls nsaccessibilitybutton

    【讨论】:

      猜你喜欢
      • 2018-04-01
      • 2015-03-05
      • 2011-05-21
      • 1970-01-01
      • 2018-10-15
      • 2017-11-18
      • 2010-12-18
      • 2015-10-27
      • 1970-01-01
      相关资源
      最近更新 更多