具有关联类型协议的协议用于通用功能

时间:2017-09-03 11:25:18

标签: swift generics swift-protocols associated-types

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

我的代码:

ReplyKeyboardMarkup

错误讯息:

  

从非协议非继承类型'Self.ObjectProtocol'

继承

Image of Xcode error

它只是这样,但我想让它更灵活:

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

如果您想要符合其他协议的通用功能,只需创建一个符合协议的associatedType T,无需额外添加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)
}