2017-09-03 10 views
1

Est-il possible de fournir un protocole de confirmation dans les fonctions génériques d'un autre protocole? J'ai essayé de le faire fonctionner comme ça, mais c'est impossible, ou j'ai fait quelques erreurs.Protocole avec type associé Protocole pour fonctions génériques

Mon code:

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

Message d'erreur:

héritage de non-protocole, type non-classe 'Self.ObjectProtocol'

Image of Xcode error

Il fonctionne seulement comme ça, mais je veux le rendre plus flexible:

protocol DataModelProtocol { 
    typealias ObjectProtocol = NSManagedObject 
    ... 
} 

Répondre

1

Ce serait peut-être être plus facile est que vous avez donné la responsabilité des types de retour aux classes d'objets eux-mêmes.

Il faudrait deux protocoles, mais il permettrait d'éviter le mélange des protocoles et génériques:

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

... Voici un exemple simple (naïve) de la façon dont les protocoles peuvent être utilisés. (J'ai choisi volontairement de ne pas utiliser les données de base pour illustrer la généralité de la solution) ...

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

} 

... En utilisant les protocoles sera un peu différent de votre approche, car vous seriez débutez de la classes d'objets plutôt que de les passer comme paramètre au modèle ...

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

Si vous voulez que les fonctions génériques d'un autre protocole conformez, il suffit de créer simplement une associatedType de T conforme au protocole, pas besoin de faire un ObjectProtocol supplémentaire:

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

Si je vais faire comme ça, il ne fonctionnera qu'avec un type par exemple, je veux qude travailler avec des parents et des enfants, qui est sous-classes de NSManagedObject Bu t dans cette solution, je vais toujours obtenir NSManagedObject –

+0

@YerkebulanAbildin pourquoi? – paper1111