Swift使用选择器参数,如闭包

时间:2015-11-11 14:07:18

标签: ios swift closures

我只是想知道是否可以将函数传递给按钮操作(通常是选择器)。

例如,通常我会说:

UIBarButtonItem(title: "Press", style: .Done, target: self, action: "functionToCall")

func functionToCall() {
    // Do something
}

但我想知道是否可以做类似的事情:

UIBarButtonItem(title: "Press", style: .Done, target: self, action: {
    // Do Something
})

我想这样做的原因是因为我的功能非常简单,看起来它更整洁,更像Swift,因为它们强调它们在封闭上的重点。

4 个答案:

答案 0 :(得分:10)

这是一种没有子类化的替代解决方案:

extension UIBarButtonItem {
    private struct AssociatedObject {
        static var key = "action_closure_key"
    }

    var actionClosure: (()->Void)? {
        get {
            return objc_getAssociatedObject(self, &AssociatedObject.key) as? ()->Void
        }
        set {
            objc_setAssociatedObject(self, &AssociatedObject.key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            target = self
            action = #selector(didTapButton(sender:))
        }
    }

    @objc func didTapButton(sender: Any) {
        actionClosure?()
    }
}

它依赖于Objective-C运行时中的关联对象来添加闭包/块属性。

设置后,它会将目标更改为自身,并将选择器指向一个新函数,如果它存在,则调用该闭包。

有了这个,你可以随时设置任何actionClosure的{​​{1}}并期望一切正常,这是一个例子:

UIBarButtonItem

答案 1 :(得分:1)

Reddit上的帖子使用自定义组件https://www.reddit.com/r/swift/comments/3fjzap/creating_button_action_programatically_using

解释了此解决方案

要使用它,虽然我必须以编程方式而不是通过故事板添加Button。我是这样做的。

{
    "title": "dfhhtryres",
    "owner": "admin",
    "code": "hfdsadfghdfh",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

答案 2 :(得分:0)

不幸的是,Apple提供的初始化程序是不可能的。它在后台运行的方式是使用反射,并且提供闭包是完全不同的,目前不支持。

您可能可以通过一些黑客攻击来创建自定义解决方案,或者Apple可能会在将来引入该解决方案。

答案 3 :(得分:0)

  • 已为Swift 5更新。
  • 实现所有具有目标的便捷初始化程序。
  • 为函数签名添加typealias,以清理语法。
  • 按照可可约定将UIBarButtonItem传递到操作处理程序中。
import UIKit

class SwiftBarButtonItem: UIBarButtonItem {
    typealias ActionHandler = (UIBarButtonItem) -> Void

    private var actionHandler: ActionHandler?

    convenience init(image: UIImage?, style: UIBarButtonItem.Style, actionHandler: ActionHandler?) {
        self.init(image: image, style: style, target: nil, action: #selector(barButtonItemPressed(sender:)))
        target = self
        self.actionHandler = actionHandler
    }

    convenience init(title: String?, style: UIBarButtonItem.Style, actionHandler: ActionHandler?) {
        self.init(title: title, style: style, target: nil, action: #selector(barButtonItemPressed(sender:)))
        target = self
        self.actionHandler = actionHandler
    }

    convenience init(barButtonSystemItem systemItem: UIBarButtonItem.SystemItem, actionHandler: ActionHandler?) {
        self.init(barButtonSystemItem: systemItem, target: nil, action: #selector(barButtonItemPressed(sender:)))
        target = self
        self.actionHandler = actionHandler
    }

    @objc func barButtonItemPressed(sender: UIBarButtonItem) {
        actionHandler?(sender)
    }
}