2015-05-19 14 views
6

ho un protocollo veloce che contiene una proprietà:Swift downcasting e di protocollo variabili

protocol WireframeProtocol: class 
{ 
    var rootViewController: UIViewController { get } 
} 

Ho poi ho una classe che implementa questo protocollo in quanto tale:

class MenuWireframe : WireframeProtocol 
{ 
    let rootViewController: UIViewController 

    init() 
    { 
     self.rootViewController = MenuViewController(nibName: "MenuViewController", bundle: nil) 
     (self.rootViewController as! MenuViewController).presenter = MenuPresenter(interactor: MenuInteractor()) 
    } 
} 

Nella mia classe Wireframe la variabile è in realtà di tipo MenuViewController ma deve essere dichiarato come UIViewController per confermare il protocollo. Devo usare (self.rootViewController as! MenuViewController) per ridurlo alla classe corretta che voglio in modo da poter accedere alle sue proprietà. Va bene nel mio semplice esempio sopra, ma non è molto leggibile, specialmente in situazioni più complesse. C'è un modo migliore per dichiarare la variabile del protocollo?

Grazie mille!

+1

Dal momento che si sta utilizzando VIPER, si potrebbe/dovrebbe dichiarare il vostro RootViewController come protocollo (il protocollo di vista), e definisce una proprietà debole, lì, che sarà il presentatore . –

+0

Ciao Daniel, è vero, ma in questo caso è per uno scopo diverso. Desidero avere un protocollo conforme a tutti i wireframe che espone un UIViewController che posso utilizzare per scopi di navigazione. Suppongo che potrei ancora usare questo protocollo di visualizzazione per questo se il protocollo è solo per UIViewControllers ... mmm Lo controllerò e tornerò da te – bennythemink

+0

@bennythemink hai controllato la mia risposta? –

risposta

3

Sì, c'è un modo migliore e questo è utilizzando protocolli generici. Per implementare che è necessario dichiarare il protocollo simile come questo:

protocol WireframeProtocol{ 

    typealias RootViewController : UIViewController 
    var rootViewController: RootViewController { get } 

} 

poi nella classe adozione impostare il tipo di RootViewController come MenuViewController

class MenuWireframe : WireframeProtocol{ 

let rootViewController: MenuViewController 

    init(){ 
     self.rootViewController = MenuViewController(nibName: "MenuViewController", bundle: nil) 
     self.rootViewController.presenter = MenuPresenter(interactor: MenuInteractor()) 
    } 
} 
+0

Ciao zellb, funziona!Ma non sono esattamente sicuro del perché. Puoi spiegarmelo per favore? – bennythemink

+1

Gli alias di tipi definiscono un nome alternativo per un tipo esistente, quindi in questo caso ho dichiarato un nuovo nome per tutti i tipi ereditati da UIViewController (in linea 'typealias RootViewController: UIViewController'). Dopo di che imposto il tipo rootViewController al nostro nuovo tipo così rootViewController var può contenere qualsiasi valore creato da classi che sono ereditate da UIViewController, quindi ora puoi impostarlo direttamente come MenuViewController senza requisiti di down-casting. Spero di essere stato chiaro –

+0

Perfetto, grazie Zellb. Per me ha senso ora :) – bennythemink

1

Hai provato questo:

protocol WireframeProtocol: UIViewController { 
    var rootViewController: UIViewController { get } 
} 

class MenuWireframe : WireframeProtocol 
{ 
    let rootViewController: WireframeProtocol 

    init() 
    { 
     //... 
    } 
} 
+0

Salve, ricevo un "tipo non di classe WireframeProtocol non può ereditare dalla classe UIViewController":/Non funzionerà in questo modo, temo. Grazie per il tuo suggerimento – bennythemink

+0

sì, ho indicato questo mancante all'inizio di Swift in un progetto. In Objective-C potremmo creare qualcosa come 'UIViewController * rootViewController;' ... –

2

Se è possibile modificare la dichiarazione di protocollo, la risposta l'uso di @ zelb. Se non è possibile, si potrebbe fare qualcosa di simile:

class MenuWireframe : WireframeProtocol 
{ 
    var rootViewController: UIViewController { 
     return menuViewController 
    } 

    let menuViewController: MenuViewController! 

    init() 
    { 
     menuViewController = MenuViewController(...) 
     //... 
    } 
} 
+0

Ciao, grazie per il tuo suggerimento. L'ho appena testato e non funziona, ho paura. Per prima cosa non posso usare "let" con questo approccio e in secondo luogo devo ancora lanciare rootViewController per digitare MenuViewController se desidero accedere alle sue proprietà :(ma grazie per il tuo suggerimento – bennythemink

+0

@bennythemink Perché non potresti usare 'let'? idea è di accedere a 'menuViewController' invece di' rootViewController' dove sai che l'oggetto dato è in effetti 'MenuWireFrame' non arbitrario' WireFrameProtocol' –

+0

Ciao, non posso usare "let" come rootViewController è ora una proprietà calcolata nel tuo suggerimento. può essere pedante ma ora significa anche che ho due proprietà invece di una nella classe.Ma ancora grazie per il suggerimento – bennythemink

Problemi correlati