3

このような実行時に UI イベントのコールバックを登録しようとしています。

func observeEvent(event: UIControlEvent){
    self.addTarget(self, action: "eventFired:", forControlEvents: event)
}

func eventFired<T>(sender: T){
    print("event fired!")
}

クラッシュし、実行時に eventFired: が見つからなかったと表示されます。これを解決するのを手伝ってもらえますか?

4

1 に答える 1

1

セレクタ文字列リテラルのターゲットとしてジェネリック関数を使用することはできません。なんで?セレクターには、ターゲットの引数のに関する情報は含まれていません。

  • セレクターのターゲットの名前 (メソッド名)
  • そして、(暗黙的に)セレクターのターゲットの引数の数。

そのため、Swift は、同じ名前と同じ数の引数を持つ非ジェネリック関数をセレクターのターゲットとして使用することさえ許可しません。これは、セレクターが使用するターゲットに関して競合が発生するためです。


たとえば、次の (遊び場) の例を考えてみましょう。

class Foo : UIView {
    var button = UIButton()

    init() {
        super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        button.addTarget(self, action: "eventFired:", forControlEvents: UIControlEvents.TouchUpInside)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func eventFired(sender: UIButton){
        print("event fired!")
    }
}

let foo = Foo()
foo.button.sendActionsForControlEvents(.TouchUpInside)
    /* event fired! */

これは意図したとおりに機能しますが、次のメソッドをFooクラスに追加してみてください。

class Foo : UIView { 

    // ...

    func eventFired(nothingToDoWithAButton: Int){
        print("another event fired!")
    }
}

上記と同じ例では、呼び出すターゲット メソッドに関してセレクターが競合しているため、エラーが発生します。

let foo = Foo()
foo.button.sendActionsForControlEvents(.TouchUpInside)
    /* error ... */

エラー: eventFiredObjective-C セレクター ' ' を持つメソッド ' 'eventFired:は、同じ Objective-C セレクターを持つ前の宣言と競合します ...

最後に、上記の追加メソッドを次のように変更すると、

class Foo : UIView { 

    // ...

    func eventFired(nothingToDoWithAButton: Int, someBool: Bool){
        print("another event fired!")
    }
}

次に、セレクターは、引数の数の違いによりeventFired(:UIButton)2 つのメソッド間で異なる可能性があるため、予想どおり、そのターゲットを見つけます。eventFired


上記から、セレクター/セレクター リテラルは、現在の形式では原始的すぎて使用できず、明確にジェネリック ターゲットを識別できないことは明らかです。セレクターには、同じ名前/同じ数の引数のターゲット間で区別できるように、ターゲット引数の型の知識を含める必要があります。

最後に、文字列リテラルとしての現在の形式のセレクターは、Swift 2.2 で非推奨になり、Swift 3.0 で削除され、新しい式構文が優先されることに注意して#selectorください。以下を参照してください。


(以下の追加書き込みOP:sコメントを編集)

ターゲットに参照型 ( ) からのさまざまなシグナルをキャッチさせ、引数...(:AnyObject)にラップされている型に応じてイベントを処理させることで、やや一般的なセレクター ターゲットを模倣することができます。AnyObject

class Foo : UIView {
    var button = UIButton()
    var sw = UISwitch()

    init() {
        super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        button.addTarget(self, action: "eventFired:", forControlEvents: .TouchUpInside)
        sw.addTarget(self, action: "eventFired:", forControlEvents: .ValueChanged)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func eventFired(sender: AnyObject){
        switch(sender) {
        case is UIButton: print("button event fired!")
        case is UISwitch: print("switch event fired!")
        case _: print("unknown event fired")
        }
    }
}

let foo = Foo()
foo.button.sendActionsForControlEvents(.TouchUpInside)
    /* button event fired! */
foo.sw.sendActionsForControlEvents(.ValueChanged)
    /* switch event fired! */
于 2016-03-07T15:55:13.627 に答える