首页 文章

在基类中实现Swift协议方法

提问于
浏览
3

我有一个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 类型 . 我当然可以在基类中实现一个不同命名的方法,然后让每个子类通过调用它的超类来实现协议's method to do the work, but that doesn' t对我来说似乎特别优雅 .

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

3 回答

  • 0

    这应该工作:

    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 . 我不知道为什么 . 所以试试真实的项目 .

  • 4

    不知道你想通过你的例子在这里完成什么,所以这是一个可能的解决方案:

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

    背后的理由

    protocol a : class
    

    声明是这样的,只有引用类型可以是扩展名 . 你可能不会对你的课程进行处理 .

  • 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 引用的类型以非常具体的方式使用 .

    经过一些实验和大量的SO研究,我终于能够使用泛型来更好地工作 . 我在我的协议中定义了如下方法:

    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 的函数类型告诉编译器在 MyBaseClassretrieve 实现中应该为 T 应用什么类型 .

相关问题