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

Posted

技术标签:

【中文标题】在 Swift 中将函数作为参数传递【英文标题】:Passing functions as parameters in Swift 【发布时间】:2016-02-16 11:38:24 【问题描述】:

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 的操作不正确,因为我到目前为止所尝试的方法都不起作用。我想我没有使用正确的语法来做我想做的事,但我确信可以做我想做的事。知道正确执行此操作的方法吗?

【问题讨论】:

“没有工作”是什么意思?请提供更具体的信息。 我的意思是我从编译器收到错误消息。如果有用,我可以包括那些。而不是我认为我的第二个函数中的语法是错误的。 我正在尝试自己寻找其他方法(例如使用泛型),但此时仍然没有成功。 现在可以了,我想通了。 Just : 使用函数名并且没有引号。谢谢! 【参考方案1】:

你的问题的答案是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

         

【讨论】:

从 Swift 3 开始,您不能将参数标签分配给函数类型。所以 MethodHandler1 应该这样写:“typealias MethodHandler1 = (String) -> Void”。从这里引用:***.com/a/39717607/380316【参考方案2】:

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

斯威夫特 5.1

闭包函数:

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

函数调用:

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

【讨论】:

【参考方案3】:

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

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

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)

现在你可以这样称呼它:

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

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

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

【讨论】:

【参考方案4】:

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

@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

【讨论】:

以上是关于在 Swift 中将函数作为参数传递的主要内容,如果未能解决你的问题,请参考以下文章

Swift:将类型作为参数传递

如何在 Swift 4 中将 Encodable 或 Decodable 作为参数传递?

是否可以在c中将函数作为参数传递? [复制]

在 C++ 中将数组作为函数参数传递

如何在类中将函数作为参数传递?

如何在 CoffeeScript 中将两个匿名函数作为参数传递?