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和两个子类,如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
及
那么你在你的控制器里做什么
[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