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

Objective-C如何强制子类实现方法?,objective-c,Objective C,这个问题的另一种表述方式是:子类是否可能是其超类的委托?我试图使我的代码在我的应用程序中可重用,并且遇到这样一种情况,子类需要实现两种方法才能正常工作。我如何才能确保发生这种情况?或者,定义这些方法的正确方式是什么 更新 我不是想暗示我希望编译器生成标志。我只是想要一种干净的方式来组织我的代码。目前我覆盖了超类的方法。使用这种方法,超类可以调用[super-methodToOverride],并且可以正常工作。但是,我觉得这不是很清楚,因为除了在某个地方添加注释之外,没有办法指定“这些是您应该重

这个问题的另一种表述方式是:子类是否可能是其超类的委托?我试图使我的代码在我的应用程序中可重用,并且遇到这样一种情况,子类需要实现两种方法才能正常工作。我如何才能确保发生这种情况?或者,定义这些方法的正确方式是什么

更新

我不是想暗示我希望编译器生成标志。我只是想要一种干净的方式来组织我的代码。目前我覆盖了超类的方法。使用这种方法,超类可以调用
[super-methodToOverride]
,并且可以正常工作。但是,我觉得这不是很清楚,因为除了在某个地方添加注释之外,没有办法指定“这些是您应该重写的方法”。

如果您的问题是“如何让编译器标记某个类没有实现某个函数”,那么我会说

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

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

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

    大概是这样的:

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

    我知道这很糟糕,但假设您需要这样做,因为您的第三方SDK需要这种设计模式,您可以使用工厂模式:

    然后假设有基类MyParentAPIClient和两个子类,如MyFacebookAPIClientMyGooglePlusAPIClient,您可以执行以下操作

    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
    

    那么你在你的控制器里做什么

    [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
    

    好消息是方法调用没有变化,因为一旦从控制器调用:

     [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];
        }
      }
    
    我们可以通过几种方式让它变得更好。看看和或


    祝你好运

    如果您想强制子类实现来自超类的方法,您可以按如下操作:

    //In super class
    - (id)someMethod:(SomeObject*)bla
    {
         [self doesNotRecognizeSelector:_cmd];
         return nil;
    }
    
    如果子类不实现此方法,并且您不需要调用,则您的应用程序将崩溃

    [super someMethod:bla];
    

    UIKit中的
    uigestureRecognitizerSubclass.h
    模式值得一看,它包含了所有应该被覆盖的受保护方法,并且头不在框架include中,它只包含在subclass.m文件中。此外,现在您可以使用
    NS\u REQUIRES\u SUPER
    标记方法,以要求重写来调用SUPER,但是它只能用于接口,而不能用于协议,因此可能会影响您的设计

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

    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
    
    NS\u协议\u需要\u显式\u实现
    @协议
    @属性(只读)id theWorstOfTimes;
    //-(无效)测试方法;//取消对测试问题的注释
    @结束
    //在本例中,ClassA采用协议。
    @接口ClassA:NSObject
    @属性(只读)id theWorstOfTimes;
    @结束
    @实现类A
    -(id)最短时间{
    return nil;//默认实现不执行任何操作
    }
    -(void)testMethod{}
    @结束
    //这个类是ClassA的子类(它也采用“协议”)。
    @接口ClassB:ClassA
    @结束
    @实现类B//预期警告{{属性'theWorstOfTimes'需要定义方法'theWorstOfTimes'-使用@synthesis、@dynamic或在此类实现中提供方法实现}
    @结束
    
    在Xcode中,您将在ClassB的
    预期警告中看到一条黄线,表示缺少属性方法<代码>NS\U协议\u需要\u显式\u实现
    只是
    属性\u((objc\u协议\u需要\u显式\u实现))的宏
    ,此代码示例从该功能的测试线束中修改

    虽然这看起来很棒,但有一个小问题。目前,这只适用于实现协议的方法,过去它也适用于方法,但2014年通过引入了一个bug,因此现在它仅限于属性方法。我给作者发了电子邮件让他们知道,所以希望它能恢复到原来的正常行为。要测试bug,您可以在协议中取消对方法的注释,您将看到ClassB中没有警告。希望您可以将某些方法更改为只读属性,以便至少从中获得一些使用。从好的方面来说,当Xcode提供“修复”问题时,它会为缺少的方法添加存根

    这是一些文件
    [super someMethod:bla];
    
    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