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

Chr*_*att 22 closures ios swift

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

例如,通常我会说:

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

func functionToCall() {
    // Do something
}
Run Code Online (Sandbox Code Playgroud)

但我想知道是否可以做以下事情:

UIBarButtonItem(title: "Press", style: .Done, target: self, action: {
    // Do Something
})
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*vid 13

这是Swift 3的更新解决方案.

class BlockBarButtonItem: UIBarButtonItem {
  private var actionHandler: ((Void) -> Void)?

  convenience init(title: String?, style: UIBarButtonItemStyle, actionHandler: ((Void) -> Void)?) {
    self.init(title: title, style: style, target: nil, action: #selector(barButtonItemPressed))
    self.target = self
    self.actionHandler = actionHandler
  }

  convenience init(image: UIImage?, style: UIBarButtonItemStyle, actionHandler: ((Void) -> Void)?) {
    self.init(image: image, style: style, target: nil, action: #selector(barButtonItemPressed))
    self.target = self
    self.actionHandler = actionHandler
  }

  func barButtonItemPressed(sender: UIBarButtonItem) {
    actionHandler?()
  }
}
Run Code Online (Sandbox Code Playgroud)

  • `func barButtonItemPressed(sender: UIBarButtonItem)` 是否需要以 `@objc` 为前缀以将其暴露给 Objective-C?很确定编译器会给你一个警告,否则。 (2认同)

Niñ*_*ipt 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?()
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

有了这个,在任何时候你都可以设置actionClosure任何一个UIBarButtonItem并期望一切正常,这是一个例子:

let button = UIBarButtonItem(
    barButtonSystemItem: .action,
    target: nil, action: nil
)
button.actionClosure = {
    print("hello")
}
Run Code Online (Sandbox Code Playgroud)


Dyl*_*lan 9

  • 为 Swift 5 更新。
  • 实现所有具有目标的便利初始值设定项。
  • typealias为函数签名添加 a以清理语法。
  • 将 传递UIBarButtonItem到符合 Cocoa 约定的操作处理程序中。
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)
    }
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*tic 0

不幸的是,Apple 提供的初始化程序无法实现这一点。它在后台工作的方式是通过反射,而提供闭包是完全不同的,目前不支持。

您也许可以通过一些黑客技术创建自定义解决方案,或者 Apple 可能会在未来推出该解决方案。