Objective-C如何强制子类实现方法?

时间:2014-03-17 19:29:42

标签: objective-c

另一种表达这个问题的方法:子类是否可能成为其超类的委托?我试图让我的代码在我的应用程序中可重用,并且有一种情况,子类需要实现两种方法才能使其正常运行。我怎样才能确保这种情况发生?或者,定义这些方法的正确方法是什么?

更新

我并不意味着我希望编译器生成标志。我只想要一种干净的方式来组织我的代码。目前我重写了超类的方法。使用该方法,超类可以调用[super methodToOverride]并且它可以工作。然而,这对我来说并不是很干净,因为没有办法指定"这些是您应该覆盖的方法"除了在某处发表评论。

6 个答案:

答案 0 :(得分:8)

在obj-c中,不可能强制子类到其超类的覆盖方法。但是你可以在超类中引发异常,因为子类没有实现某个方法。 但是子类可以是其超类的委托,如果超类不实现某些方法,并且您可以强制委托实现这些方法,如果超类指定协议,即必需方法,并且子类采用它。

答案 1 :(得分:6)

如果要强制子类实现超类中的方法,可以执行以下操作:

//In super class
- (id)someMethod:(SomeObject*)bla
{
     [self doesNotRecognizeSelector:_cmd];
     return nil;
}

如果子类不实现此方法且您不需要致电

,您的应用就会崩溃
[super someMethod:bla];

答案 2 :(得分:3)

在编译时无法做到这一点。但是,您可以在基类中引发异常。

这样的事情:

@throw [NSException exceptionWithName:NSInternalInconsistencyException
                               reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
                             userInfo:nil];

答案 3 :(得分:2)

如果您的问题是"我怎样才能让编译器标记某个类没有实现某个功能"然后我会说

  1. 使用非可选方法定义协议 - "默认情况下,协议中声明的所有方法都是必需的方法。这意味着符合协议的任何类都必须实现这些方法。"
  2. 定义一个声明它实现协议的类(" stub")
  3. 现在编写存根类的子类时,如果强制方法没有实现,编译器会将其标记为错误

答案 4 :(得分:1)

我知道这很糟糕,但是假设你需要这样做,因为你的3rdParty SDK需要这种设计模式,你可以使用工厂模式:

然后假设基类 MyParentAPIClient 和两个子类,如 MyFacebookAPIClient MyGooglePlusAPIClient ,并且您执行类似

的操作
self.myAPIClient = [MyParentAPIClient alloc] initWithAPIKey:apiKey];

您已定义

@@interface MyParentAPIClient : NSObject {
}

-(void)callAPI;

@end

并且你已经在两个子类中重写了这个

@implementation MyFacebookAPIClient
 -(void)callAPI {
    [super callAPI];
    // do something specific for this api client
 }
@end

@implementation MyGooglePlusAPIClient
-(void)callAPI {
    [super callAPI];
    // do something specific for this api client
 }
@end

然后你正在控制器中

[self.myAPIClient callAPI];

但正在调用超类 MyParentAPIClient 方法。

现在你可以在基类中做一个工厂,如:

-(void)callAPI {
    if([self isKindOfClass:[MyFacebookAPIClient class]]) {
        [((MyFacebookAPIClient*)self) callAPI];
    } else if([self isKindOfClass:[MyGooglePlusAPIClient class]]) {
       [((MyGooglePlusAPIClient*)self) callAPI];
    }
 }

当然这有一个缺点就是不要在现在变成的子类中调用super:

@implementation MyFacebookAPIClient
 -(void)callAPI {
    // [super callAPI]; the factory method called that
    // do something specific for this api client
 }
@end

    @implementation MyGooglePlusAPIClient
    -(void)callAPI {
        // [super callAPI]; being called in the factory
        // do something specific for this api client
     }
    @end

好消息是,一旦你从控制器打电话,方法调用就没有变化:

 [self.myAPIClient callAPI];

您将接听电话

[MyParentAPIClient callAPI]; // parent class
[MyFacebookAPIClient callAPI]; // sub class

另一个缺点是父类必须已知子类实例。

现在,如果我们看看工厂:

if([self isKindOfClass:[MyFacebookAPIClient class]]) {
        [((MyFacebookAPIClient*)self) callAPI];
    } else if([self isKindOfClass:[MyGooglePlusAPIClient class]]) {
       [((MyGooglePlusAPIClient*)self) callAPI];
    }
  }

我们可以通过多种方式让它变得更好。请查看Dynamic type cast from id to class in objective cIs there an equivalent to C++'s dynamic cast in Objective-C?Objective-C dynamic_cast?

祝你好运!

答案 5 :(得分:0)

来自UIKit的UIGestureRecognizerSubclass.h模式值得一看,它具有应该被覆盖的所有受保护方法,并且该标头不在框架中,它只包含在子类的.m文件中。此外,现在您可以使用NS_REQUIRES_SUPER标记方法以要求覆盖来调用super,但是它只能用于接口,而不能用于协议,因此可能会影响您的设计。

对于超高级代码,AppKit中的NSAccessibilityProtocols.h使用协议标记来要求子类重新实现方法,即使已经由超类实现。下面是一个示例,您可以将其粘贴到当前打开的Xcode项目的标题中:

NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION
@protocol Protocol
@property (readonly) id theWorstOfTimes;
// -(void)testMethod; // uncomment to test problem
@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
}
-(void)testMethod{}
@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

在Xcode中,你会在ClassB的expected-warning看到黄色线,表示缺少属性方法。 NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION只是__attribute__((objc_protocol_requires_explicit_implementation))的一个宏,此代码示例是从该功能here的测试工具中修改的。

虽然这看起来很棒但是有一个小问题。目前,这仅适用于实现协议的方法,它也适用于方法,但是2014年通过misunderstanding on the purpose of this feature引入了一个错误,因此现在仅限于属性方法。我已经通过电子邮件发送作者让他们知道,所以希望它改回原来的正确行为。要测试该错误,您可以取消注释协议中的方法,您将看到ClassB中没有警告。希望您可以将一些方法更改为只读属性,以至少从中获取一些用途。在Xcode提供“修复”问题时,它会为缺少的方法添加存根。

以下是NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION的一些文档: ImplementingAccessibilityforCustomControls nsaccessibilitybutton

如果您使用过这个,那么如果您还没有成为ObjC专家,那就拍拍自己吧!