ios 在 Swift 中将函数作为参数传递

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33717313/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:14:46  来源:igfitidea点击:

Passing functions as parameters in Swift

iosswiftfunctionparameter-passing

提问by Michel

I have the following function working as I expect, in iOS 8:

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

I would like to make something like the following, in order to pass as arguments the methods to be executed when one or the other of the buttons are going to be touched:

我想做如下事情,以便将要触摸一个或另一个按钮时要执行的方法作为参数传递:

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

Obviously I am not doing the right thing with firstSelector and secondSelector, because what I have tried up to now did not work. I suppose I am not using the right syntax for what I want, but I am sure it is possible to do what I would like to do. Any idea of the way to do it properly?

显然我对 firstSelector 和 secondSelector 没有做正确的事情,因为我迄今为止尝试过的方法没有奏效。我想我没有为我想要的东西使用正确的语法,但我确信可以做我想做的事。知道如何正确地做到这一点吗?

回答by iPrabu

Oneword answer for your question is Closures

您的问题的 Oneword 答案是Closures

The Default Syntax for closures is () -> ()

闭包的默认语法是 () -> ()

Instead of Selector you could directly mention the method definition

您可以直接提及方法定义而不是 Selector

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

But using this will create readability problems so i suggest you to use typeAlias

但是使用它会造成可读性问题,所以我建议你使用 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()
}

You can call your method like this

你可以像这样调用你的方法

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

         }
}

回答by got2jam

Just in case anyone else stumbles upon this. I worked out an updated simple solution for Swift 5.1 while I was working through this for while building a global alert utility for a project.

以防万一其他人偶然发现这一点。在为项目构建全局警报实用程序时,我为 Swift 5.1 制定了一个更新的简单解决方案。

Swift 5.1

斯威夫特 5.1

Function with Closure:

带闭包的函数:

func showSheetAlertWithOneAction(messageText: String, dismissButtonText: String, actionButtonText : String, presentingView : NSWindow, actionButtonClosure: @escaping () -> Void) {
        let alert = NSAlert()
        alert.messageText = messageText
        alert.addButton(withTitle: actionButtonText)
        alert.addButton(withTitle: dismissButtonText)
        alert.beginSheetModal(for: presentingView) { (response) in
            if response == .alertFirstButtonReturn {
                actionButtonClosure()
            }
        }
    }

Function Called:

调用的函数:

showSheetAlertWithOneAction(messageText: "Here's a message", dismissButtonText: "Nope", actionButtonText: "Okay", presentingView: self.view.window!) {
                                            someFunction()
                                }

回答by Alix Huerta

Adding to got2jam's answer... If you're working with UIAlertController

添加到got2jam的答案...如果您正在使用 UIAlertController

The generic function to show an alert with closure:

显示关闭警报的通用函数:

func showAlertAction(title: String, message: String, actionClosure: @escaping () -> Void){
  let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
  alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: {(action: UIAlertAction!) in actionClosure()}))
  self.present(alertController, animated: true, completion: nil)
}

Now you can call it like that:

现在你可以这样称呼它:

showAlertAction(title: "This is the title", message: "This is the message") {
   self.close()
}

in this case, closeis the particular UIAlertAction to execute

在这种情况下,close是要执行的特定 UIAlertAction

func close(){
  dismiss(animated: true, completion: nil)
}

回答by Blake Martin

I wrote this routine based on various site examples. Here is how I call the routine...

我根据各种站点示例编写了此例程。这是我如何调用例程...

@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")
}

You can pass in button options and the functions to performed when the buttons are selected. Took a little time to figure out how to pass functions as parameters, but appears to work fine now. I did encounter a strange problem trying to use loops to dynamically add buttons, and finally gave up and used a switch/case. I included the loop code I tried to use, if someone can figure out what I was doing wrong let me know. Thanks.

您可以传入按钮选项和选择按钮时要执行的功能。花了一点时间弄清楚如何将函数作为参数传递,但现在似乎工作正常。我确实遇到了一个奇怪的问题,试图使用循环来动态添加按钮,最后放弃并使用了 switch/case。我包含了我尝试使用的循环代码,如果有人能找出我做错了什么,请告诉我。谢谢。

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

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