将 UIButton 连接到关闭?(迅速,目标行动) [英] Hooking up UIButton to closure? (Swift, target-action)

查看:12
本文介绍了将 UIButton 连接到关闭?(迅速,目标行动)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将 UIButton 连接到一段代码——根据我的发现,在 Swift 中执行此操作的首选方法仍然是使用 addTarget(target: AnyObject?, action: Selector, forControlEvents: UIControlEvents) 函数.这使用 Selector 构造大概是为了向后兼容 Obj-C 库.我想我理解 Obj-C 中 @selector 的原因——能够引用方法,因为在 Obj-C 中方法不是一等值.

I want to hook up a UIButton to a piece of code – from what I have found, the preferred method to do this in Swift is still to use the addTarget(target: AnyObject?, action: Selector, forControlEvents: UIControlEvents) function. This uses the Selector construct presumably for backwards compatibility with Obj-C libraries. I think I understand the reason for @selector in Obj-C – being able to refer to a method since in Obj-C methods are not first-class values.

不过,在 Swift 中,函数是一等值.有没有办法将 UIButton 连接到闭包,类似于:

In Swift though, functions are first-class values. Is there a way to connect a UIButton to a closure, something similar to this:

// -- Some code here that sets up an object X

let buttonForObjectX = UIButton() 

// -- configure properties here of the button in regards to object
// -- for example title

buttonForObjectX.addAction(action: {() in 

  // this button is bound to object X, so do stuff relevant to X

}, forControlEvents: UIControlEvents.TouchUpOutside)

据我所知,上述情况目前是不可能的.考虑到 Swift 看起来它的目标是变得非常实用,这是为什么呢?这两个选项显然可以共存以实现向后兼容性.为什么这不像 JS 中的 onClick() 那样工作?似乎唯一将 UIButton 连接到目标-动作对的方法是使用仅出于向后兼容性原因而存在的东西(Selector).

To my knowledge, the above is currently not possible. Considering that Swift looks like it's aiming to be a quite functional, why is this? The two options could clearly co-exist for backwards compatibility. Why doesn't this work more like onClick() in JS? It seems that the only way to hook up a UIButton to a target-action pair is to use something that exists solely for backwards compatibility reasons (Selector).

我的用例是在循环中为不同的对象创建 UIButton,然后将每个对象连接到一个闭包.(设置标签/在字典中查找/子类化 UIButton 是肮脏的半解决方案,但我对如何在功能上做到这一点感兴趣,即这种关闭方法)

My use case is to create UIButtons in a loop for different objects, and then hook each up to a closure. (Setting a tag / looking up in a dictionary / subclassing UIButton are dirty semi-solutions, but I'm interested in how to do this functionally, ie this closure approach)

推荐答案

您可以通过添加辅助闭包包装器 (ClosureSleeve) 并将其作为关联对象添加到控件中来将 target-action 替换为闭包以使其保留.

You can replace target-action with a closure by adding a helper closure wrapper (ClosureSleeve) and adding it as an associated object to the control so it gets retained.

这与 n13 的答案中的解决方案类似.但我发现它更简单、更优雅.更直接地调用闭包并自动保留包装器(作为关联对象添加).

This is a similar solution to the one in n13's answer. But I find it simpler and more elegant. The closure is invoked more directly and the wrapper is automatically retained (added as an associated object).

class ClosureSleeve {
    let closure: () -> ()

    init(attachTo: AnyObject, closure: @escaping () -> ()) {
        self.closure = closure
        objc_setAssociatedObject(attachTo, "[(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
    }

    @objc func invoke() {
        closure()
    }
}

extension UIControl {
    func addAction(for controlEvents: UIControlEvents = .primaryActionTriggered, action: @escaping () -> ()) {
        let sleeve = ClosureSleeve(attachTo: self, closure: action)
        addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
    }
}

用法:

button.addAction {
    print("Hello")
}

它会自动挂钩到 .primaryActionTriggered 事件,该事件等于 UIButton 的 .touchUpInside.

It automatically hooks to the .primaryActionTriggered event which equals to .touchUpInside for UIButton.

这篇关于将 UIButton 连接到关闭?(迅速,目标行动)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆