2017-05-20 4 views
0

Okay, so hat ich dieses Protokoll MenuEntry, die ich mag eine Tableview zu füllen verwenden:Swift: Shop Art der Implementierung des Protokolls in statischer Var der Protokollerweiterung

protocol MenuEntry { 
    static var title: String { get } 
    static func entrySelected(_ menuController: MenuController) 
} 

Ich mag dieses Protokoll an verschiedenen Orten implementieren und lassen Sie den Gegenstand selbst entscheiden, was zu tun ist. Es könnte ein UIViewController sein, die das Protokoll oder eine einfache Struktur implementiert, die dann eine Funktion im Menü nennt sich:

struct SomeEntry: MenuEntry { 
    static var title: String { return "Some Entry" } 
    static func entrySelected(_ menuController: MenuController) { 
     menuController.doSomething() 
    } 
} 

Jetzt möchte ich die MenuControllers Datenquelle bauen, aber ohne tatsächlich die Einträge Instanziieren weil vor allem meine Ansicht-Controller sind nicht unbedingt verfügbar, wenn die MenuControllers-Datenquelle aufgefüllt ist. Deshalb verwende ich statische var/func in MenuEntry. Derzeit kann ich einfach das tun, um die Datenquelle zu füllen:

let dataSource: [MenuEntry.Type] = [SomeEntry.self] 

Und es scheint ziemlich gut zu funktionieren. Ich kann die Einträge holen und die entsprechenden Funktionen aufrufen:

dataSource.first?.title //Gives me "Some Entry" 

Jetzt kommt der knifflige Teil. Ich dachte, ich könnte wirklich klug sein und eine Protokollerweiterung schaffen, in dem ich alle Typen verweisen, in denen ich das Protokoll wie so implementieren:

extension MenuEntry { 
    static var someEntry: MenuEntry.Type { return SomeEntry.self } 
    //... 
} 

Und sie dann später über MenuEntry.someEntry verwenden. Doch auf menuentry someEntry Zugriff gibt mir eine Fehlermeldung:

error: static member 'someEntry' cannot be used on protocol metatype 'MenuEntry.Protocol' 

Also meine Frage ist: Was bin ich fehlt? Versuche ich nur, die Sprache in einer Weise zu missbrauchen, die nicht beabsichtigt ist, oder mache ich nur etwas falsch?

SOLUTION

Von der akzeptierten Antwort unten, here, wie ich jetzt Dinge. Zuerst müssen wir die erwähnte Struktur (keine Notwendigkeit für eine Klasse I guess):

struct MenuEntries {} 

Dann, wo immer ich das menuentry Protokoll implementieren, habe ich auch diese Struktur erweitern und den Eintrag hinzuzufügen, etwa so:

struct SomeEntry: MenuEntry { 
    static var title: String { return "Some Entry" } 
    static func entrySelected(_ menuController: MenuController) { 
     menuController.doSomething() 
    } 
} 

extension MenuEntries { 
    static var someEntry: MenuEntry.Type { return SomeEntry.self } 
} 

Das letzte, was meine Datenquelle ist wie so zu erstellen:

let dataSource: [MenuEntry.Type] = [MenuEntries.someEntry, ...] 

okay, jetzt habe ich eine Liste aller Menüeinträge an einem Ort. Der Nachteil ist, dass ich daran denken muss, MenuEntries jedes Mal zu erweitern. Außer dass es eine magische Möglichkeit gibt, eine Struktur auf einer bedingten Basis zu erweitern, ist mir nicht bekannt. Aber ich denke, das ist einfach übertrieben und einfach nicht möglich.

Antwort

0

Von The Swift Book

A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements.”

Ihre Erweiterung versucht Funktionalität zu implementieren direkt in das Protokoll, aber dies ist nicht erlaubt; Nur eine Klasse, Struktur oder Enumeration, die das Protokoll übernimmt, kann Funktionalität bereitstellen.

Sie könnten eine Klasse definieren, die Ihre Klassen Menü zurück:

class MenuFactory { 
    static var someEntry: MenuEntry.type { return SomeEntry.self } 
} 
+0

Ihnen sehr danken. Das erklärt es gut! Ich ging jedoch mit einer Struktur statt einer Klasse (siehe die Lösung in meiner Antwort) – xxtesaxx

Verwandte Themen