如何定义符合协议的"类"对象类型?



考虑下面的Objective-C协议声明,它只需要类方法:

@protocol TDWMethoding<NSObject>
+ (void)foo;
+ (void)bar;
@end

假设我需要从方法返回符合此协议的Class的实例,我该如何指定返回类型?

- (nullable /*return-type*/)instantiateMethoding {
Class instance = ... // some implementation
if ([instance conformsToProtocol:@protocol(TDWMethoding)]) {
return instance;
}
return nil;
}
关于如何表达/*return-type*/,我考虑了许多工作选项,但每个选项都有自己的缺点:
  1. Class-这样它不会暴露一致性。这是哪种Class?它是做什么的?它完全符合协议吗?
  2. Class<TDWMethoding>-这看起来像是一个可行的解决方案,甚至被其他开发人员建议了几次(这里和这里),但我个人觉得它不一致和误导:当我们有一个形式Type<Protocol> *instance的变量,它通常意味着协议类方法应该发送到实例的类([[instance class] foo])而不是实例本身([instance foo]);
  3. id<TDWMethoding>并返回类的实例-这是一致的,但它要求我实例化类,这是冗余的,并且阻止我隐藏符合NS_UNAVAILABLE宏协议的实用程序类的构造函数。

是否有更好的语义来表达这样的返回类型?

Class<TDWMethoding>是正确的。这并不矛盾。当某些东西的类型是Class时,您可以向它发送类方法。当某些东西是一个实例,并且你想要发送给类时,你访问它的-class

也就是说,这看起来很奇怪,很可能意味着您过度使用了Class方法。你应该认真考虑sharedInstance是否是一个更好的模型。

但是如果您想要识别类型,Class<TDWMethoding>是正确的,尽管id可能更常见,如如何强制转换类对象以符合协议中所讨论的。

在深入研究了Objective-C编程语言文档之后,我实际上找到了这种场景的确切答案:

协议不能用于类型化对象。只有实例可以静态类型化为协议,就像只有实例可以静态类型化为类一样。(然而,在运行时,类和实例都响应conformsToProtocol:消息。)

这意味着它不被支持我应该用不同的方式实现它。(例如,使用单例模式,正如Rob的回答所建议的那样)

解决方案是根本不使用这些协议。为什么?因为它不灵活

应该是:

@protocol TDWMethoding
- (void)foo;
- (void)bar;
@end

然后你将能够做任何你想做的,例如,你将能够为你的类创建包装器,这将实现你的协议。

@interface TDWMethodingModel<TDWMethoding>
@property (nonatomic, readonly) void (^fooCaller)(void);
@property (nonatomic, readonly) void (^barCaller)(void);
- (instancetype)initWithFooCaller:(void (^)(void))fooCaller barCaller:(void (^)(void))barCaller NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
@implementation TDWMethodingModel
- (instancetype)initWithFooCaller:(void (^)(void))fooCaller barCaller:(void (^)(void))barCaller {
self = [super init];
if (nil == self) {
return nil;
}
_fooCaller = fooCaller;
_barCaller = barCaller;
return self;
}
- (void)foo {
self.fooCaller();
}
- (void)bar {
self.barCaller();
}
@end

:

- (id<TDWMethoding>)instantiateMethoding
{
static id<TDWMethoding> methoding;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
methoding = [[TDWMethodingModel alloc] initWithFooCaller:^{
[SomeClass foo];
} barCaller:^{
[SomeClass bar];
}];
});
return methoding;
}

相关内容

  • 没有找到相关文章

最新更新