12

メニューバーボタンを持つビューコントローラーのセットがあります。それらのviewControllerが採用するためのプロトコルを作成しました。また、プロトコルを拡張してデフォルトの機能を追加しました。

私のプロトコルは次のようになります

protocol CenterViewControllerProtocol: class {

    var containerDelegate: ContainerViewControllerProtocol? { get set }

    func setupMenuBarButton()
}

そして、拡張機能は次のようになります。

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

私のviewControllerはプロトコルを採用しています-

class MapViewController: UIViewController, CenterViewControllerProtocol {

    weak var containerDelegate: ContainerViewControllerProtocol?

    override func viewDidLoad() {
        super.viewDidLoad()

        setupMenuBarButton()
    }
}

ボタンがうまく表示されるようになりましたが、クリックするとアプリがクラッシュします

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

ViewController 内にメソッドを実装すると、正常に動作します。しかし、プロトコルに準拠するすべてのviewControllerでコードを複製します。

ここで何か間違っていますか?前もって感謝します。

4

4 に答える 4

0

現時点では、プロトコル拡張の使用はサポートされていないようです。ここでのfluidsonicの回答によると:

いずれにせよ、セレクターを介して使用する予定のすべての関数は、動的または @objc でマークする必要があります。これにより、@objc をこのコンテキストで使用できないというエラーが発生した場合、あなたがしようとしていることは単にサポートされていません。」

あなたの例では、これを回避する1つの方法は、タップされるたびにブロックを呼び出す UIBarButtonItem のサブクラスを作成することだと思います。containerDelegate?.toggleSideMenu()次に、そのブロック内で呼び出すことができます。

于 2015-11-26T05:16:38.327 に答える
0

これはコンパイルされますが、Xcode7.3 ベータ版でもクラッシュするため、最終的にアクションのターゲットとして醜いスーパー クラスを使用する必要があります。

于 2016-02-01T16:43:13.030 に答える
0

これは古い質問ですが、私も同じ問題に遭遇し、完璧ではないかもしれない解決策を思いつきましたが、それが私が考えることができる唯一の方法です.

どうやらSwift 3でも、ターゲットアクションをプロトコル拡張に設定することはできません。func menuTapped()ただし、プロトコルに準拠するすべての ViewControllers にメソッドを実装しなくても、目的の機能を実現できます。

まず、プロトコルに新しいメソッドを追加しましょう

protocol CenterViewControllerProtocol: class {

    var containerDelegate: ContainerViewControllerProtocol? { get set }

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

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

拡張機能を次のように変更します

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

ボタンのアクションは、拡張機能では "menuTapped" ではなく "menuTappedInVC" であることに注意してください。そして、準拠するすべての ViewController は、CenterViewControllerProtocolこのメソッドを実装する必要があります。

あなたのViewControllerで、

class MapViewController: UIViewController, CenterViewControllerProtocol {

    weak var containerDelegate: ContainerViewControllerProtocol?

    override func viewDidLoad() {
        super.viewDidLoad()

        setupMenuBarButton()
    }

    func menuTappedInVC()
    {
      self.menuTapped()
    }

VC にメソッドを実装するだけmenuTappedInVC()で、それがターゲット アクション メソッドになります。menuTappedその中で、プロトコル拡張に既に実装されているタスクを委任できます。

于 2017-03-14T18:57:17.110 に答える