2015-11-25 9 views
11

Ho un set di controller di visualizzazione che avrà un pulsante della barra dei menu. Ho creato un protocollo per quei viewControllers da adottare. Inoltre, ho esteso il protocollo per aggiungere funzionalità predefinite.L'aggiunta dell'azione di destinazione nell'estensione del protocollo non riesce

mio protocollo sembra,

protocol CenterViewControllerProtocol: class { 

    var containerDelegate: ContainerViewControllerProtocol? { get set } 

    func setupMenuBarButton() 
} 

E, l'estensione sembra così,

extension CenterViewControllerProtocol where Self: UIViewController { 

    func setupMenuBarButton() { 
     let barButton = UIBarButtonItem(title: "Menu", style: .Done, target: self, action: "menuTapped") 
     navigationItem.leftBarButtonItem = barButton 
    } 

    func menuTapped() { 
     containerDelegate?.toggleSideMenu() 
    } 
} 

mio viewController adotta il protocollo -

class MapViewController: UIViewController, CenterViewControllerProtocol { 

    weak var containerDelegate: ContainerViewControllerProtocol? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     setupMenuBarButton() 
    } 
} 

ho avuto il pulsante per visualizzare bene, ma quando faccio clic su di esso, l'app si blocca con

[AppName.MapViewController menuTapped]: unrecognized selector sent to instance 0x7fb8fb6ae650 

Se implemento il metodo all'interno di ViewController, funziona correttamente. Ma dovrei duplicare il codice in tutti i viewControllers conformi al protocollo.

Qualcosa che sto facendo male qui? Grazie in anticipo.

risposta

0

Sembra che l'utilizzo delle estensioni del protocollo non sia supportato in questo momento. Secondo fluidsonic's risposta here:

In ogni caso tutte le funzioni che si intende utilizzare tramite il selettore devono essere contrassegnati con dinamico o @objc. Se questo si traduce in un errore che @objc non possono essere utilizzati in questo contesto, allora ciò che si sta cercando di fare è semplicemente non supportato ".

Nel tuo esempio, penso che un modo per aggirare questo sarebbe quello di creare un sottoclasse di UIBarButtonItem che chiama un blocco ogni volta che viene toccato.Poi si può chiamare containerDelegate?.toggleSideMenu() all'interno di quel blocco

0

Questo compila ma si blocca anche in Xcode7.3 Beta quindi alla fine si dovrebbe usare una brutta super classe come bersaglio dell'azione, Suppongo che sia quello che tu e io stiamo cercando di evitare

0

Questa è una vecchia domanda, ma ho anche incontrato lo stesso problema p con una soluzione che potrebbe non essere perfetta ma è l'unico modo in cui potrei pensare.

Apparentemente anche in Swift 3, non è possibile impostare un'azione di destinazione sull'estensione del protocollo. Ma puoi ottenere la funzionalità desiderata senza implementare il tuo metodo func menuTapped() in tutti i ViewControllers conformi al tuo protocollo.

prima aggiungiamo nuovi metodi per il protocollo

protocol CenterViewControllerProtocol: class { 

    var containerDelegate: ContainerViewControllerProtocol? { get set } 

    //implemented in extension 
    func setupMenuBarButton() 
    func menuTapped() 

    //must implement in your VC 
    func menuTappedInVC() 
} 

Ora cambiare la vostra estensione come questo

extension CenterViewControllerProtocol where Self: UIViewController { 

     func setupMenuBarButton() { 
      let barButton = UIBarButtonItem(title: "Menu", style: .Done, target: self, action: "menuTappedInVC") 
      navigationItem.leftBarButtonItem = barButton 
     } 

     func menuTapped() { 
      containerDelegate?.toggleSideMenu() 
     } 
    } 

Notate ora l'azione del pulsante è "menuTappedInVC" nel proprio interno, non "menuTapped". E ogni ViewController conforme a CenterViewControllerProtocol deve implementare questo metodo.

Nella tua ViewController,

class MapViewController: UIViewController, CenterViewControllerProtocol { 

    weak var containerDelegate: ContainerViewControllerProtocol? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     setupMenuBarButton() 
    } 

    func menuTappedInVC() 
    { 
     self.menuTapped() 
    } 

Tutto quello che dovete fare è implementare menuTappedInVC() metodo nella VC e che sarà il vostro metodo di destinazione-azione. All'interno di questo è possibile delegare tale attività a menuTapped che è già implementata nell'estensione del protocollo.