【问题标题】:Base class with class method call closure with child class type具有子类类型的类方法调用闭包的基类
【发布时间】:2018-05-18 23:34:41
【问题描述】:

我有一个带有类 func 的基类:

class BaseModel
{
    class func getObjectWithId(_ id: String, completionHandler: @escaping (<???>) -> ())
    {
       // does query, calls completionHandler with matching object
    }
}

我有两个子类:

class Cat: BaseModel { //whatever }
class Dog: BaseModel { //whatever }

我希望能够在子类上调用该类方法,并使用子类类型的对象调用完成处理程序:

Cat.getObjectWithId("1") { (theCat) in
 // I want theCat to be of type Cat, not BaseModel
}

Dog.getObjectWithId("1") { (theDog) in
 // I want theDog to be of type Dog, not BaseModel
}

我修改了泛型,但承认这不是我的强项...

  • 我不想在每个基类 b/c 中为此编写代码,除了类型之外它是相同的(即我不希望每个孩子都必须实现一个协议)。

  • 我不想要一个将类型作为参数的类方法。我真的很喜欢我的示例方法调用的简单性。

【问题讨论】:

    标签: swift generics


    【解决方案1】:

    你可以试试这个代码:

    class BaseModel
    {
        class func getObjectWithId<T: BaseModel>(_ id: String, completionHandler: @escaping (T) -> ())
        {
           // does query, calls completionHandler with matching object
        }
    }
    

    但是你必须明确地专门化这样的类型

    Cat.getObjectWithId("1") { (theCat: Cat) in
        // I want theCat to be of type Cat, not BaseModel
    }
    
    Dog.getObjectWithId("1") { (theDog: Dog) in
        // I want theDog to be of type Dog, not BaseModel
    }
    

    但更安全的方法是在您想要的每个类中复制函数 getObjectWithId

    【讨论】:

    • 到目前为止的两个答案中,这看起来更好......虽然我对调用者基本上必须将其转换为正确的类型并不感到兴奋。
    • 我接受这个答案 b/c 它给了我一个通用签名的工作示例,让我朝着正确的方向前进。
    【解决方案2】:

    我最终在 Anton 的建议和我原本不想做的事情之间使用了一种混合方法:

    1. 我几乎完全按照 Anton 的方式创建了该方法的基本版本,除了它还需要数据类型(我原本想避免的):

      class BaseModel
      {
          class func getObjectWithId<T: BaseModel>(_ id: String, type: T.Type, completionHandler: @escaping (T?) -> ())
          {
             // does query, calls completionHandler with matching object
          }
      }
      
    2. 然后,子类有自己的专用方法来调用该基类方法:

      class Dog: BaseModel
      {
          class func getDogWithId(_ dogId: String, completionHandler: @escaping (Dog?) -> ()
          {
              BaseModel.getObjectWithId(dogId, objectType: Dog.self) { (dog) in
              completionHandler(dog)
              }
          }
      }
      

    缺点:在每个子类中为这个方法创建一个签名很烦人(它甚至不再是继承,尽管出于其他原因我仍然需要基类)。

    Pro:这很好,因为我不必在每个子类中重复代码的内容,

    亲:我不必每次调用子类方法时都强制转换结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-14
      • 2021-12-25
      • 2022-01-03
      • 2012-06-28
      • 1970-01-01
      • 2011-01-22
      • 2017-12-13
      • 2011-01-05
      相关资源
      最近更新 更多