关于C#:iOS子类和强制方法

iOS Subclassing and compulsory methods

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

为了安全起见。

干杯


在Xcode(使用clang等)中,我喜欢使用__attribute__((unavailable(...)))标记抽象类,这样,如果尝试使用抽象类,就会收到错误/警告。

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

例子

在基类@interface中,标记"abstract"方法:

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

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

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

这样可以做到:

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

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


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

最接近的方法是在超类中引发一个异常,这样子类就被"强制"覆盖了。

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


您可以要求子类在编译时使用以下LLVM特性来实现属性(为什么不使用下面的方法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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))的一个宏,这个代码示例是从这个特性的测试工具中修改的。

这种方法过去也适用于方法,但2014年由于对其用途的误解而引入了一个bug,现在它只适用于属性,我给作者发了电子邮件,希望他们能意识到它是如何改变的。要测试这个bug,您可以向协议中添加一个方法,您将看到ClassB中没有警告。希望您可以将一些方法更改为只读属性,以至少从中获得一些使用。

以下是有关NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION的一些文档:实现客户控制的可访问性"不可访问性"按钮

如果你用了这个,那么如果你还没有成为一个objc专家的话,请拍拍自己的背!


在RJStalking的启发下,我以一种更令人满意的方式解决了这个问题:

在前缀中,定义:

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

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

1
- (void) getDataIdentifier abstract;

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

1
'getDataIdentifier' is unavailable: abstract method

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