在基类中实现Swift协议方法

时间:2014-11-19 04:25:52

标签: swift

我有一个Swift协议,它定义了如下方法:

protocol MyProtocol {

    class func retrieve(id:String) -> Self?
}

我有几个不同的类符合这个协议:

class MyClass1 : MyProtocol { ... }
class MyClass2 : MyProtocol { ... }
class MyClass3 : MyProtocol { ... }

每个子类中retrieve方法的实现几乎相同。我想将这些函数的通用实现拉入符合协议的共享超类:

class MyBaseClass : MyProtocol
{
    class func retrieve(id:String) -> MyBaseClass?   
}

class MyClass1 : MyBaseClass { ... }
class MyClass2 : MyBaseClass { ... }
class MyClass3 : MyBaseClass { ... }

这种方法的问题在于我的协议将retrieve方法的返回类型定义为类型Self,这是我最终想要的。但是,因此我无法以这种方式在基类中实现retrieve,因为它会导致MyClass1MyClass2MyClass3的编译器错误。这些类中的每一个都必须符合它们从MyBaseClass继承的协议。但是因为该方法是使用返回类型MyBaseClass实现的,并且协议要求它是MyClass1,所以它表示我的类不符合协议。

我想知道是否有一种干净的方法来实现一种协议方法,该方法在基类中的一个或多个方法中引用Self类型。我当然可以在基类中实现一个不同命名的方法,然后让每个子类通过调用其超类的方法来实现协议来完成工作,但这对我来说似乎并不特别优雅。

我在这里缺少一种更简单的方法吗?

3 个答案:

答案 0 :(得分:4)

这应该有效:

protocol MyProtocol {
    class func retrieve(id:String) -> Self?
}

class MyBaseClass: MyProtocol {

    required init() { }

    class func retrieve(id:String) -> Self? {
        return self()
    }
}

required init() { }是确保从MyBaseClass派生的任何子类具有init()初始化程序所必需的。

请注意,此代码会崩溃Swift Playground。我不知道为什么。所以试试真实的项目。

答案 1 :(得分:0)

不确定你想要通过你的例子完成什么,所以这是一个可能的解决方案:

protocol a : class {
  func retrieve(id: String) -> a?
}

class b : a {
  func retrieve(id: String) -> a? {
    return self
  }
}

背后的原因
protocol a : class

声明是为了只有引用类型可以是扩展名。当您处理类时,您可能不希望传递值类型(struct)。

答案 2 :(得分:0)

我已经将@rintaro的答案标记为正确的答案,因为它确实回答了我提出的问题。但是,我发现这个解决方案太有限了,所以我发布了我在这里遇到的其他问题的替代答案。

上一个答案的限制是它只适用于Self所代表的类型(在我的示例中为MyClass1MyClass2MyClass3)用于协议或作为类方法的返回类型。所以当我有这个方法时

class func retrieve(id:String) -> Self?
一切都按照我的希望运作。但是,当我解决这个问题时,我意识到这个方法现在需要是异步的,不能直接返回结果。所以我用类方法尝试了这个:

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) -> ())

然后在我的基类中执行以下操作:

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`
    }
}

当我想要检索MyClass1类型的实例时,我会执行以下操作:

class MyClass1 : MyBaseClass {    
    func success(result:MyClass1} {
        ...
    }
    func failure(error:NSError) {
        ...
    }
    class func doSomething {
        MyClass1.retrieve("objectID", successCallback:success, failureCallback:failure)
    }

通过此实现,success的函数类型告诉编译器Tretrieve的实现中MyBaseClass应该应用哪种类型。

相关问题