2017年10月31日火曜日

Selectorの書き方

Timerとかで処理先のメソッドを指定するSelectorだけど、書式が変わったし、引数を渡したい場合などがよくわかってないのでまとめ。

基本書式

override func viewDidLoad() {
    super.viewDidLoad()

    let t = Timer.init(timeInterval: 0.5,
                       target: self,
                       selector: #selector(ViewController.hoge(_:)),
                       userInfo: userInfo,
                       repeats: false)
    t.fire()

}

@objc func hoge(_ sender:Timer) -> Void {
    print("タイマー実行")
}

上のコードは0.5秒後にhoge()を一度だけ実行する。
selectorで指定するメソッドは、Swift4から頭に@objcを付けてやらなければいけない。
これはどうやらObjective-C由来の仕様だからで、今までは推定して実行してくれてたけど、もうやってくれないんだそうな。ケチだな。

selfがViewControllerの場合、Selectorは以下のとおり。

hoge()に引数がある場合

⭕️ #selector(ViewController.hoge(_:))
⭕️ #selector(ViewController.hoge)
⭕️ #selector(hoge(_:))
⭕️ #selector(hoge)

普通に後ろに()を付けたり、以前の書き方のように" "で囲むのはダメ。
❌ #selector(ViewController.hoge())
❌ #selector("ViewController.hoge(_:)")
❌ #selector("ViewController.hoge")

hoge()に引数がない場合

⭕️ #selector(ViewController.hoge)
⭕️ #selector(hoge)

 #selector(hoge(_:))
 #selector(hoge())

メソッドの引数は使えない?

引数を渡したくて、普通に書いてやっても、エラーになってしまう。
❌ selector: #selector(hoge(str: "文字"))

@objc func hoge(str:String) -> Void {
    print("タイマー実行 \(str)")
}

それでも引数を渡すのだ!

引数の渡し方は以下のようにuserInfo経由のものとなる。
複数の引数を渡したいなら、配列や辞書に入れて渡すのかな?
hogeの方ではsender.userInfoで取り出せる。

let userInfo = "引数がわり"
let t = Timer.init(timeInterval: 0.5,
                   target: self,
                   selector: #selector(hoge(_:)),
                   userInfo: userInfo,
                   repeats: false)


@objc func hoge(_ sender:Timer) -> Void {
    let str = sender.userInfo
    print("タイマー実行 \(String(describing: str))")
}

senderのかわりに別の名前でもいい。型名は送り手側のクラス名になるのだな。
@objc func hoge(_ s:Timer) -> Void {
    let str = s.userInfo
    print("タイマー実行 \(String(describing: str))")
}

めんどくさいね

書き方がちょくちょく変わるし、引数の渡し方も特殊だし、総じて面倒臭い。
もっと簡単な書き方にしやがれと思うのだが。

0 件のコメント:

コメントを投稿