簡體   English   中英

如何定義符合協議的`Class` object 類型?

[英]How to define a `Class` object type conforming to a protocol?

考慮以下 Objective-C 協議聲明,它只需要 class 方法:

@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形式的變量時,它通常意味着協議 class 方法應該發送到實例的 class ( [[instance class] foo] ) 而不是實例本身 ( [instance foo] );
  3. id<TDWMethoding>並返回 class 的實例 - 這是一致的,但它需要我實例化 class,這既是多余的,又阻止我隱藏符合NS_UNAVAILABLE宏協議的實用程序類的構造函數。

是否有更好的語義來表達這種返回類型?

Class<TDWMethoding>是正確的。 這並不矛盾。 當某物的類型為Class時,您向其發送 class 方法。 當某物是一個實例,並且您想發送到 class 時,您可以訪問它的-class

也就是說,這看起來確實很奇怪,並且可能意味着您過度使用了 Class 方法。 為此,您應該認真考慮sharedInstance是否更好 model。

但是,如果您想識別類型, Class<TDWMethoding>是正確的,盡管id可能更常見,如如何將 Class object 轉換為符合協議中所述。

在深入了解Objective-C Programming Language 文檔后,我實際上找到了這種情況的確切答案:

協議不能用於鍵入 class 對象。 只有實例可以靜態類型化為協議,就像只有實例可以靜態類型化為 class 一樣。(但是,在運行時,類和實例都會響應 conformsToProtocol conformsToProtocol:消息。)

這意味着它不受支持,我應該以不同的方式實現它。 (例如使用 singleton 模式,如Rob 的回答中所建議)

解決方案是根本不使用此類協議。 為什么? 因為它不靈活。

它應該只是:

@protocol TDWMethoding

- (void)foo;
- (void)bar;

@end

然后你將能夠做任何你想做的事,例如你將能夠為你的 class 創建包裝器,這將實現你的協議。

@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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM