在基类中实现Swift协议方法
我有一个定义如下方法的Swift协议:在基类中实现Swift协议方法,swift,Swift,我有一个定义如下方法的Swift协议: protocol MyProtocol { class func retrieve(id:String) -> Self? } class MyBaseClass : MyProtocol { class func retrieve<T:MyBaseClass>(id:String, successCallback: (T) -> (), failureCallback: (NSError) -> ())
protocol MyProtocol {
class func retrieve(id:String) -> Self?
}
class MyBaseClass : MyProtocol {
class func retrieve<T:MyBaseClass>(id:String, successCallback: (T) -> (), failureCallback: (NSError) -> ()) {
// Perform retrieve logic and on success invoke successCallback with an object of type `T`
}
}
class MyClass1 : MyBaseClass {
func success(result:MyClass1} {
...
}
func failure(error:NSError) {
...
}
class func doSomething {
MyClass1.retrieve("objectID", successCallback:success, failureCallback:failure)
}
我有几个不同的类将符合此协议:
class MyClass1 : MyProtocol { ... }
class MyClass2 : MyProtocol { ... }
class MyClass3 : MyProtocol { ... }
class MyBaseClass : MyProtocol
{
class func retrieve(id:String) -> MyBaseClass?
}
class MyClass1 : MyBaseClass { ... }
class MyClass2 : MyBaseClass { ... }
class MyClass3 : MyBaseClass { ... }
每个子类中retrieve
方法的实现几乎相同。我想将这些函数的通用实现拉入符合协议的共享超类:
class MyClass1 : MyProtocol { ... }
class MyClass2 : MyProtocol { ... }
class MyClass3 : MyProtocol { ... }
class MyBaseClass : MyProtocol
{
class func retrieve(id:String) -> MyBaseClass?
}
class MyClass1 : MyBaseClass { ... }
class MyClass2 : MyBaseClass { ... }
class MyClass3 : MyBaseClass { ... }
这种方法的问题是,我的协议将retrieve
方法的返回类型定义为typeSelf
,这是我最终真正想要的。但是,因此,我无法以这种方式在基类中实现检索,因为它会导致MyClass1
、MyClass2
和MyClass3
的编译器错误。这些类中的每一个都必须符合它们从MyBaseClass
继承的协议。但是,由于该方法是使用返回类型MyBaseClass
实现的,并且协议要求它必须是MyClass1
,因此它表示我的类不符合协议
我想知道是否有一种干净的方法可以实现一个协议方法,该方法在基类中的一个或多个方法中引用Self
类型。当然,我可以在基类中实现一个不同名称的方法,然后让每个子类通过调用其超类的方法来实现协议,但这在我看来并不特别优雅
这里有没有我缺少的更直接的方法?这应该可以:
protocol MyProtocol {
class func retrieve(id:String) -> Self?
}
class MyBaseClass: MyProtocol {
required init() { }
class func retrieve(id:String) -> Self? {
return self()
}
}
required init()
请注意,此代码会导致Swift Playerd崩溃。我不知道为什么。因此,请尝试使用real project。仅通过您的示例不确定您希望在这里实现什么,因此这里有一个可能的解决方案:
protocol a : class {
func retrieve(id: String) -> a?
}
class b : a {
func retrieve(id: String) -> a? {
return self
}
}
背后的理由
protocol a : class
声明是这样的,所以只有引用类型可以作为扩展。在处理类时,您可能不希望传递值类型(struct)。我已将@rintaro的答案标记为正确答案,因为它确实回答了我提出的问题。然而,我发现这个解决方案太有限了,所以我在这里发布了一个备选答案,我发现它适用于任何遇到这个问题的人
前面答案的局限性在于,它仅在协议中使用由Self
表示的类型(在我的示例中是MyClass1
,MyClass2
,或MyClass3
)或作为类方法的返回类型时才起作用。所以当我有了这个方法
class func retrieve(id:String) -> Self?
一切都如我所愿。然而,当我完成这项工作时,我意识到这个方法现在需要是异步的,并且不能直接返回结果。所以我用class方法尝试了这一点:
class func retrieve(id:String, successCallback:(Self) -> (), failureCallback:(NSError) -> ())
我可以将此方法放入MyProtocol
中,但是当我尝试在MyBaseClass
中实现时,我得到以下编译器错误:
Error:(57, 36) 'Self' is only available in a protocol or as the result of a class method; did you mean 'MyBaseClass'?
因此,除非以非常具体的方式使用Self
引用的类型,否则我真的不能使用这种方法
经过一些实验和大量的研究,我终于能够使用泛型让一些东西更好地工作。我在协议中定义的方法如下:
class func retrieve(id:String, successCallback:(Self) -> (), failureCallback:(NSError) -> ())
然后在我的基类中,我做了以下工作:
protocol MyProtocol {
class func retrieve(id:String) -> Self?
}
class MyBaseClass : MyProtocol {
class func retrieve<T:MyBaseClass>(id:String, successCallback: (T) -> (), failureCallback: (NSError) -> ()) {
// Perform retrieve logic and on success invoke successCallback with an object of type `T`
}
}
class MyClass1 : MyBaseClass {
func success(result:MyClass1} {
...
}
func failure(error:NSError) {
...
}
class func doSomething {
MyClass1.retrieve("objectID", successCallback:success, failureCallback:failure)
}
在这个实现中,success
的函数类型告诉编译器在MyBaseClass
中retrieve
的实现中应该为T
应用什么类型,我将这个答案标记为正确答案,因为它确实回答了我所问的问题。然而,我发现它不足以满足我的需求,因为我对其他因素没有足够的了解。我将为感兴趣的人发布我自己的答案和详细信息。这并不是我想要的,因为它告诉Swift我正在返回一个实现协议“a”的对象,而不是返回一个类b的实例。此外,它不允许我实现一个名为“c”的“b”子类并让检索方法返回一个“c”实例