2014-09-10 31 views
29

In Objective-C, è possibile scrivere qualcosa di simile:Swift: proprietà conforme a una classe specifica e nello stesso tempo per più protocolli

@property(retain) UIView<Protocol1, Protocol2, ...> *myView; 

Ma come posso scrivere questo codice in rapida?

so già come fare un alloggio è conforme alla molti protocolli, ma non funziona utilizzando l'eredità:

var myView: ??? protocol<Protocol1, Protocol2, ...> 

Edit:

Io uso molti UIView sottotipi come UIImageView, UILabel o altri, e ho bisogno di utilizzare alcune delle proprietà UIView oltre ad alcuni metodi definiti nei protocolli. Nel peggiore dei casi potrei creare un UIViewProtocol con le proprietà necessarie, ma vorrei sapere se è possibile in Swift dichiarare una proprietà/variabile con un tipo e un protocollo con cui conformarsi.

+1

Non credo sia possibile come si potrebbe in Objective-C. Potresti dirci qualcosa in più sui protocolli? Pensa che potrebbe esserci un approccio diverso che sarà più adatto a Swift. –

+0

Non capisco perché dovresti provare a forzare una classe come UIView o UILabel per conformarsi ad un protocollo a cui non è già conforme, nel qual caso non è necessario specificarlo. Stai estendendo queste classi per conformarti ai nuovi protocolli? –

+0

@ TomErikStøwer Penso che questa sia la soluzione migliore. Sto ancora imparando Swift e vorrei sapere se era possibile come in Objective-C. Sì, li estendo per conformarmi ai nuovi protocolli, quindi non ci sono problemi. –

risposta

23

Si può fare questo con una classe generica utilizzando un where clause:

una clausola WHERE consente di richiedere che un tipo associato conforme ad un certo protocollo, e/o che certi parametri di tipo e associato i tipi sono gli stessi

Per usarlo, rendere la classe vostra proprietà è definita in una classe generica con un type constraint per verificare se il type parameter per il vostro annuncio corrispondente alla classe di base desiderata e protocolli.

Per esempio specifico, potrebbe essere simile a questa:

class MyViewController<T where T: UIView, T: Protocol1, T: Protocol2>: UIViewController { 
    var myView: T 

    // ... 
} 
+1

Grande risposta. Sapete come questo è diverso da 'classe MyViewController : UIViewController {}'? – Kamchatka

+0

Sono abbastanza sicuro che sia esattamente lo stesso. Immagino di essere stato coinvolto nell'uso di 'where' e di non aver provato il formato più conciso. –

+6

Per utilizzare questa soluzione, è necessario specificare T se si inizializza il controller. Non è un problema se c'è un singolo oggetto nella proprietà, ma nel mio caso ho un array che può contenere più oggetti istanziati da diverse sottoclassi della classe base. @ Mike Come affronteresti questo problema? –

3

Uno e probabilmente un po 'brutto uno dei modi per farlo, è quello di creare un protocollo di wrapper per UIView:

protocol UIViewRef { 
    var instance: UIView { get } 
} 

Ora è possibile creare un protocollo che implementa Protocol1, Protocol2 e UIViewRef, che sta per essere usato per ottenere il UIView stesso:

protocol MyUIViewProtocol: UIViewRef, Protocol1, Protocol2 { } 

E ultimo passo sarà l'attuazione di protocolli UIViewRef per i vostri UIView s, che, in voi caso, come ho capito, già implementano Protocol1 e Protocol2:

// SomeOfMyViews already implements Protocol1 and Protocol2 
extension SomeOfMyUIViews: MyUIViewProtocol { 
    var instance: UIView { return self } 
} 

Come risultato abbiamo MyUIViewProtocol, gli esecutori di cui detengono un riferimento a un UIView e ciascuno di essi implementa Protocol1 e Protocol2. Un avvertimento però - per ottenere il UIView stesso, abbiamo bisogno di chiedere il suo riferimento dalla proprietà instance . Ad esempio

// Lets say we're somewhere in a UIViewController 
var views: [SomeOfMyUIView] = // Get list of my views 
views.forEach { self.view.addSubview($0.instance) } 
4

In Swift 4 è finalmente possibile.È possibile dichiarare la variabile di qualche classe conforme al protocollo allo stesso tempo, come questa:

class ClassA { 
    var someVar: String? 
} 

protocol ProtocolA {} 

class ClassB { 
    var someOptional: (ClassA & ProtocolA)? // here is optional value 
    var some: ClassA & ProtocolA // here is non-optional value; need to provide init though :) 
} 
+0

Potresti dirmi come fornire quell'iniz? Ci sto provando da un po 'senza successo .. – jake1981

+0

@ jake1981, init (alcuni: ClassA e ProtocolA) { self.some = alcuni } –

Problemi correlati