2015-11-25 12 views
11

Mam zestaw kontrolerów widoku, które będą miały przycisk paska menu. Stworzyłem protokół dla tych viewControllers do przyjęcia. Rozszerzyłem też protokół, aby dodać domyślne funkcje.Dodawanie działania docelowego w przedłużeniu protokołu kończy się niepowodzeniem

Mój protokół wygląda,

protocol CenterViewControllerProtocol: class { 

    var containerDelegate: ContainerViewControllerProtocol? { get set } 

    func setupMenuBarButton() 
} 

I, rozszerzenie wygląda tak,

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() 
    } 
} 

My viewController przyjmuje Protocol -

class MapViewController: UIViewController, CenterViewControllerProtocol { 

    weak var containerDelegate: ContainerViewControllerProtocol? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     setupMenuBarButton() 
    } 
} 

mam przycisk, aby wyświetlić ładnie, ale kiedy go klikam, aplikacja rozłącza się z

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

Jeśli zaimplementuję metodę wewnątrz ViewController, działa dobrze. Ale będę duplikować kod we wszystkich viewControllerach, które są zgodne z protokołem.

Wszystko, co robię źle tutaj? Z góry dzięki.

Odpowiedz

0

Wygląda na to, że używanie rozszerzeń protokołu nie jest w tym momencie obsługiwane. Według fluidsonic's odpowiedź here:

W każdym razie wszystkie funkcje ma być używane przez selektor powinny być oznakowane dynamiczny lub @objc. Jeśli spowoduje to błąd, którego nie można użyć w tym kontekście, nie jest to obsługiwane. "

W twoim przykładzie, myślę, że jednym ze sposobów jest stworzenie podklasa UIBarButtonItem, która dzwoni do bloku, gdy jest dotknięty.Możesz zadzwonić pod numer containerDelegate?.toggleSideMenu() w tym bloku.Alternator:

0

To kompiluje się, ale zawiesza się również w Xcode7.3 Beta, więc powinieneś użyć brzydkiej super klasy jako celu akcji, że przypuszczam, że to jest to, czego ty i ja próbujemy uniknąć.

0

To jest stare pytanie, ale też wpadłem na ten sam problem i przyszedłeś p z rozwiązaniem, które może nie być idealne, ale jest to jedyny sposób, jaki mogłem wymyślić.

Wygląda na to, że nawet w Swift 3 nie można ustawić docelowego działania dla rozszerzenia protokołu. Ale można osiągnąć pożądaną funkcjonalność bez implementacji metody func menuTapped() we wszystkich kontrolerach ViewController zgodnych z protokołem.

najpierw dodajmy nowe metody do protokołu

protocol CenterViewControllerProtocol: class { 

    var containerDelegate: ContainerViewControllerProtocol? { get set } 

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

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

teraz zmienić przedłużeniu jak ten

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() 
     } 
    } 

Zawiadomienie teraz działanie przycisku jest „menuTappedInVC” w rozszerzeniu, a nie „menuTapped”. I każdy ViewController, który jest zgodny z CenterViewControllerProtocol, musi wdrożyć tę metodę.

W swojej ViewController,

class MapViewController: UIViewController, CenterViewControllerProtocol { 

    weak var containerDelegate: ContainerViewControllerProtocol? 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     setupMenuBarButton() 
    } 

    func menuTappedInVC() 
    { 
     self.menuTapped() 
    } 

Wszystko co musisz zrobić, to wdrożenie menuTappedInVC() metodę w swojej VC i to będzie twoja metoda docelowego działania. W ramach tego można przekazać to zadanie z powrotem do menuTapped, które jest już zaimplementowane w rozszerzeniu protokołu.

Powiązane problemy