web-dev-qa-db-ja.com

Swiftで関数をパラメーターとして渡す

IOS 8では、期待どおりに機能する次の機能があります。

func showConfirmBox(msg:String, title:String,
    firstBtnStr:String,
    secondBtnStr:String,
    caller:UIViewController) {
        let userPopUp = UIAlertController(title:title,
            message:msg, preferredStyle:UIAlertControllerStyle.Alert)
        userPopUp.addAction(UIAlertAction(title:firstBtnStr, style:UIAlertActionStyle.Default,
            handler:{action in}))
        userPopUp.addAction(UIAlertAction(title:secondBtnStr, style:UIAlertActionStyle.Default,
            handler:{action in}))
        caller.presentViewController(userPopUp, animated: true, completion: nil)
}

いずれかのボタンがタッチされたときに実行されるメソッドを引数として渡すために、次のようなものを作成したいと思います。

func showConfirmBox(msg:String, title:String,
    firstBtnStr:String, firstSelector:Selector,
    secondBtnStr:String, secondSelector:Selector,
    caller:UIViewController) {
        let userPopUp = UIAlertController(title:title,
            message:msg, preferredStyle:UIAlertControllerStyle.Alert)
        userPopUp.addAction(UIAlertAction(title:firstBtnStr, style:UIAlertActionStyle.Default,
            handler:{action in caller.firstSelector()}))
        userPopUp.addAction(UIAlertAction(title:secondBtnStr, style:UIAlertActionStyle.Default,
            handler:{action in caller.secondSelector()}))
        caller.presentViewController(userPopUp, animated: true, completion: nil)
}

私が今まで試したことはうまくいかなかったので、明らかに、私はfirstSelectorとsecondSelectorで正しいことをしていません。私は私が望むものに正しい構文を使用していないと思いますが、私がやりたいことをすることは可能であると確信しています。それを適切に行う方法のアイデアはありますか?

27
Michel

あなたの質問に対する一言の答えは Closures です

クロージャのデフォルトの構文は() -> ()

Selectorの代わりに、メソッド定義を直接言及することができます

func showConfirmBox(msg:String, title:String,
    firstBtnStr:String, firstSelector:(sampleParameter: String) -> returntype,
    secondBtnStr:String, secondSelector:() -> returntype,
    caller:UIViewController) {
    //Your Code
}

しかし、これを使用すると読み取り可能な問題が発生するため、typeAliasを使用することをお勧めします

typealias MethodHandler1 = (sampleParameter : String)  -> Void
typealias MethodHandler2 = ()  -> Void

func showConfirmBox(msg:String, title:String,
                    firstBtnStr:String, firstSelector:MethodHandler1,
                    secondBtnStr:String, secondSelector:MethodHandler2) {

    // After any asynchronous call
    // Call any of your closures based on your logic like this
    firstSelector("FirstButtonString")
    secondSelector()
}

このようにメソッドを呼び出すことができます

func anyMethod() {
   //Some other logic 

   showConfirmBox(msg: "msg", title: "title", firstBtnStr: "btnString", 
         firstSelector: { (firstSelectorString) in
              print(firstSelectorString) //this prints FirstButtonString
         }, 
         secondBtnStr: "btnstring") { 
           //Invocation comes here after secondSelector is called

         }
}
57
iPrabu

このルーチンは、さまざまなサイトの例に基づいて作成しました。ルーチンを呼び出す方法は次のとおりです...

@IBAction func buttonClick(_ sender: Any) {
    SS_Alert.createAlert(parmTitle: "Choose", parmMessage: "Please select Yes or No", parmOptions: ["Yes","No","Cancel"], parmFunctions: [testYes, testNo, nil])
}

func testYes() {
    print("yes")
}

func testNo() {
    print("no")
}

ボタンが選択されたときに実行するボタンオプションと機能を渡すことができます。関数をパラメーターとして渡す方法を理解するのに少し時間がかかりましたが、今はうまく機能しているようです。ループを使用して動的にボタンを追加しようとすると、奇妙な問題が発生し、最終的にスイッチ/ケースをあきらめて使用しました。誰かが私が間違っていることを理解できるなら、私に知らせて、使用しようとしたループコードを含めました。ありがとう。

https://github.com/blakeguitar/iOS/blob/0e243d13cb2decd6e1dbe134a8a046c2caed3876/SS_Alert.Swift

1
Blake Martin