2015-01-19 9 views
5

In Objective-C v'è un modo per dichiarare un conforme variabile a una classe e un insieme di protocolli simili:Swift: proprietà Array con elementi conformi ad una classe e protocolli multipli simultaneamente

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

In Swift Vorrei dichiarare un array (in realtà come una proprietà di una classe) con elementi di un tipo definito da questo modello.

In this question esiste una soluzione per descrivere il tipo di una proprietà autonoma rendendo la classe generica e vincolando il tipo di conseguenza. Per istanziare una classe di questo tipo sarebbe necessario specificare il tipo esatto. Questo non è un problema per una proprietà standalone, ma in un array dovrebbe essere possibile memorizzare elementi con tipi esatti diversi.

C'è un modo per esprimere questo in Swift?

+0

Non sono sicuro se ho capito bene, ma se gli elementi dell'array sono tutti dello stesso tipo, usare '[]()' per istanziarlo. –

+0

@ThomasKilian No, non lo sono. Questo è esattamente il punto. –

+0

@LukasKubanek è richiesto, che solo gli oggetti conformi a questi protocolli sono memorizzati nell'array? –

risposta

4

Grazie a @SebastianDressler e @Mike-S ho scoperto che non esiste un modo semplice per esprimere questo in Swift.

Cosa si può fare se è per vincolare il tipo di oggetto che si desidera aggiungere alla matrice in questo modo:

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

Casting gli elementi dalla matrice quando il suo tipo è definito come quello del la classe base dei protocolli non è possibile, perché il compilatore non vede alcuna relazione tra questi tipi.

Per poter eseguire il cast sulla classe base o su uno dei protocolli, è necessario dichiarare il tipo come AnyObject.

var array: [AnyObject] = [] 

e il casting per i protocolli funziona solo quando sono annotati con @objc (vedi https://stackoverflow.com/a/24318145/670119).

1

Nel caso in cui si desideri memorizzare solo oggetti conformi ai propri protocolli, è possibile creare un altro protocollo che erediti gli altri, ad es.

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

Ora è possibile creare l'array corrispondente

var objects : [ C ] 

È possibile memorizzare qualsiasi oggetto, purché conforme alla C -Protocollo e quindi di A e B così:

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

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

La tecnica dietro è Protocol Inheritance.

Aggiornamento IMO questo non è possibile con lo Array di Swift. Perché, puoi memorizzare un tipo ereditato da una classe base o AnyObject, che non soddisfa i tuoi vincoli. Ma è possibile creare un wrapper che controlli l'oggetto che si tenta di aggiungere all'array e lo rifiuta se non si adatta ai vincoli.

+0

Ciò di cui ho bisogno è anche una conformità a una classe base. Per comporre i protocolli ho anche potuto definire il tipo usando il 'protocollo ', ma sto cercando un modo per combinarlo con un tipo di classe. –

+0

Scusa, ma non capisco il punto. Se c'è un 'Foo' conforme ai protocolli' A' e 'B', e vuoi immagazzinare oggetti con' Foo' e quindi 'A' e' B' in un array, questi oggetti devono ereditare da 'Foo'. ancora. Altrimenti non è garantito che soddisfi questi vincoli. –

+0

Forse non ero troppo chiaro nella mia risposta, ma 'Foo' non eredita dai protocolli. È solo un requisito di tipo aggiuntivo, come nella dichiarazione Obj-C di cui sopra. –