2015-01-19 3 views
5

In Objective-C gibt es eine Möglichkeit, eine variable Conforming zu einer Klasse und eine Reihe von Protokollen wie folgt zu erklären:Swift: Array-Eigenschaft mit Elementen zu einer Klasse und mehrere Protokollen entsprechen, gleichzeitig

BaseClass<Protocol1, Protocol2> *variable = ... 

In Swift Ich möchte ein Array (eigentlich als Eigenschaft einer Klasse) mit Elementen eines durch dieses Muster definierten Typs deklarieren.

In this question gibt es eine Lösung zum Beschreiben des Typs einer eigenständigen Eigenschaft, indem Sie die Klasse generisch machen und den Typ entsprechend einschränken. Um eine solche Klasse zu instanziieren, wäre es notwendig, den genauen Typ anzugeben. Dies ist kein Problem für eine eigenständige Eigenschaft, aber in einem Array sollte es möglich sein, Elemente mit verschiedenen exakten Typen zu speichern.

Gibt es eine Möglichkeit, dies in Swift auszudrücken?

+0

Nicht sicher, ob ich dich richtig verstanden habe, aber wenn die Array-Elemente alle vom selben Typ sind, dann benutze '[]()' um es zu instanziieren. –

+0

@ThomasKilian Nein, sind sie nicht. Das ist genau der Punkt. –

+0

@LukasKubanek ist es erforderlich, dass nur Objekte, die diesen Protokollen entsprechen, im Array gespeichert werden? –

Antwort

4

Dank @SebastianDressler und @Mike-S habe ich herausgefunden, dass es keinen einfachen Weg gibt, dies in Swift auszudrücken.

Was Sie jedoch tun, ist die Art des Elements, das Sie das Array wie folgt hinzufügen möchten einschränken:

func addItem<T where T: BaseClass, T: Protocol1, T: Protocol2>(item: T) { 
    self.array.append(item) 
} 

die Elemente aus dem Array Casting, wenn seine Art als eine der definiert ist Die Basisklasse der Protokolle ist nicht möglich, da der Compiler keine Beziehung zwischen diesen Typen sieht.

Um in die Basisklasse oder eines der Protokolle umwandeln zu können, muss der Typ als AnyObject deklariert werden.

var array: [AnyObject] = [] 

und Gießen zu den Protokollen funktioniert nur, wenn sie mit @objc (siehe https://stackoverflow.com/a/24318145/670119) kommentiert werden.

1

In dem Fall, dass Sie nur Objekte speichern möchten, die Ihren Protokollen entsprechen, können Sie ein anderes Protokoll erstellen, das die anderen erbt, z.

protocol A { } 
protocol B { } 
protocol C : A, B { } 

Jetzt können Sie die entsprechenden Array erstellen

var objects : [ C ] 

Sie ein beliebiges Objekt speichern kann, solange es dem C -Protokoll entspricht und damit zu A und B auch:

class Foo : X { } 
class Bar : X { } 

objects.append(Foo()) // [ Foo ] 
objects.append(Bar()) // [ Foo, Bar ] 

Die Technik dahinter ist Protocol Inheritance.

aktualisieren IMO ist dies mit dem Array von Swift nicht machbar. Sie können entweder einen von einer Basisklasse geerbten Typ oder AnyObject speichern, der Ihren Einschränkungen nicht entspricht. Sie können jedoch möglicherweise einen Wrapper erstellen, der das Objekt, das Sie an Ihr Array anhängen möchten, überprüft und es ablehnt, wenn es nicht zu den Einschränkungen passt.

+0

Was ich brauche, ist auch eine Übereinstimmung mit einer Basisklasse. Zum Erstellen der Protokolle könnte ich auch den Typ mit 'Protokoll ' definieren, aber ich suche nach einer Möglichkeit, es mit einem Klassentyp zu kombinieren. –

+0

Sorry, aber dann verstehe ich es nicht richtig. Wenn es ein "Foo" gibt, das den Protokollen "A" und "B" entspricht, und Sie Objekte mit "Foo" und somit "A" und "B" in einem Array speichern möchten, müssen diese Objekte von "Foo" erben nochmal. Andernfalls kann nicht garantiert werden, dass diese Einschränkungen erfüllt werden. –

+0

Vielleicht war ich nicht so klar in meiner Antwort, aber "Foo" erbt nicht von den Protokollen. Es ist nur eine zusätzliche Typanforderung - genauso wie in der Obj-C-Deklaration oben. –

Verwandte Themen