【问题标题】:Protocol with associatedtype Protocol for Generic functions带有关联类型的协议 通用函数的协议
【发布时间】:2017-09-03 11:25:18
【问题描述】:

是否可以在另一个协议的通用功能中提供确认协议? 我试着让它像这样工作,但这是不可能的,或者我犯了一些错误。

我的代码:

protocol DataModelProtocol {
  associatedtype ObjectProtocol: Protocol
  func fetchObjects<T: ObjectProtocol>() -> [T]?
  func fetch<T: ObjectProtocol>(object: T) -> T?
  func delete<T: ObjectProtocol>(allObjectOf type: T.Type)
  func insert<T: ObjectProtocol>(_ object: T)
  func save<T: ObjectProtocol>(_ object: T)
  func update<T: ObjectProtocol>(_ object: T)
  func delete<T: ObjectProtocol>(_ object: T)
}

错误信息:

继承自非协议、非类类型'Self.ObjectProtocol'

Image of Xcode error

它只能这样工作,但我想让它更灵活:

protocol DataModelProtocol {
  typealias ObjectProtocol = NSManagedObject
  ...
}

【问题讨论】:

    标签: swift generics swift-protocols associated-types


    【解决方案1】:

    如果您将返回类型的责任交给对象类本身,这可能会更容易。

    您将需要两个协议,但它会避免混合协议和泛型:

    // The first protocol is for the base class of data objects
    protocol DataProtocol  
    {}
    
    // The protocol provides the "typed" equivalents of the model's
    // data manipulation methods.
    // By using an extension to DataProtocol, this only needs to
    // be done once for all models and data objects.
    extension DataProtocol
    {
       static func fetchObjects(from model:DataModelProtocol) -> [Self]?
       { return model.fetchObjects(object: Self.self) as! [Self]? }
    
       static func fetch(from model:DataModelProtocol) -> Self? 
       { return model.fetch(object: Self.self) as! Self? }
    
       // ...
    }
    
    // The second protocol is for the data models 
    // It requires implementation of the data manipulation methods
    // using the general "DataProtocol" rather than any specific class
    // The actual instances it produces must be of the appropriate class
    // however because they will be type casted by the DataProtocol's
    // default methods
    protocol DataModelProtocol 
    {  
      func fetchObjects(object:DataProtocol.Type) -> [DataProtocol]?
      func fetch(object:DataProtocol.Type) -> DataProtocol?
      // ... and so on
    }
    

    ... 这是一个如何使用协议的简单(天真)示例。 (我故意选择不使用核心数据来说明解决方案的普遍性) ...

    // The base class (or each one) can be assigned the DataProtocol
    // (it doesn't add any requirement)
    
    class LibraryObject : DataProtocol
    {}
    
    class Author: LibraryObject   
    { 
      var name = "" 
    }
    
    class Book: LibraryObject
    {
       var title  = ""
    }
    
    // This is a simple class that implements a DataModelProtocol
    // in a naive (and non-core-data way)
    
    struct LibraryModel:DataModelProtocol
    {
      var authors:[Author] = [ Author(), Author() ]
    
      var books:[Book] = [ Book(), Book(), Book(), Book(), Book() ]
    
      func fetchObjects(object: DataProtocol.Type) -> [DataProtocol]?
      { 
         return object == Book.self   ?  books 
              : object == Author.self ?  authors
              : nil
      }
    
      func fetch(object:DataProtocol.Type) -> DataProtocol?
      { return nil }
    
    }
    

    ... 使用协议将与您的方法有点不同,因为您将从对象类开始,而不是将它们作为参数传递给模型 ...

    var library  = LibraryModel()
    let allBooks = Book.fetchObjects(from:library) // this almost reads like english
    

    【讨论】:

      【解决方案2】:

      如果要符合其他协议的泛型函数,只需创建符合协议的TassociatedType 即可,无需额外创建ObjectProtocol

      protocol DataModelProtocol {
        associatedtype T: Protocol
        func fetchObjects<T>() -> [T]?
        func fetch<T>(object: T) -> T?
        func delete<T>(allObjectOf type: T.Type)
        func insert<T>(_ object: T)
        func save<T>(_ object: T)
        func update<T>(_ object: T)
        func delete<T>(_ object: T)
      }
      

      【讨论】:

      • 如果我这样做,它只适用于一种类型例如我想使用父类和子类来获取函数,它们是 NSManagedObject 的子类但是在这个解决方案中我总是会得到 NSManagedObject
      • @YerkebulanAbildin 为什么?
      猜你喜欢
      • 2016-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-14
      相关资源
      最近更新 更多