【问题标题】:Strongly typed selectors in swiftswift中的强类型选择器
【发布时间】:2014-10-19 09:12:57
【问题描述】:

我想知道我们可以在 swift 中实现强类型选择器吗?例如,如果我稍后在我的视图控制器中有一个名为 buttonTapped(sender: AnyObject) 的方法,当我们将该方法作为目标添加到某个按钮时,我们可以说

button.addTarget(self, selector:ViewController.buttonTapped(self), forControlEvents: .TouchUpInside)

【问题讨论】:

  • Swift 中没有“选择器”的概念。理想情况下,应为此目的使用闭包。
  • 我知道没有。但是我们可以为Selector类型添加一个扩展并使其解析方法吗?
  • 我不这么认为,但是您可以使用addAction(action:UIButton->Void forControlEvents events:UIControlEvent) 之类的方法将扩展名添加到UIButton
  • @BryanChen 如果您展示了 addAction 方法的实现作为答案,我会投赞成票。

标签: ios cocoa swift


【解决方案1】:

过时了。请参阅Claus Jørgensen's answer 了解 Swift 2.2+

Swift 中没有“选择器”的概念。理想情况下,应为此目的使用闭包。

你真正想要的是这样的

button.addAction(forControlEvents: .TouchUpInside) {
   // watch out for retain cycle, use weak or unowned accordingly
    ViewController.buttonTapped(self)
}

您可以使用此代码(未经测试,但它应该为您提供一个起点)

public class ClosureWrapper : NSObject
{
    let _callback : Void -> Void
    init(callback : Void -> Void) {
        _callback = callback
    }
    
    public func invoke()
    {
        _callback()
    }
}

var AssociatedObjectHandle: UInt8 = 0

extension UIControl
{
    public func addAction(forControlEvents events: UIControlEvents, withCallback callback: Void -> Void)
    {
        let wrapper = ClosureWrapper(callback)
        addTarget(wrapper, action:"invoke", forControlEvents: events)
        // as @newacct said in comment, we need to retain wrapper object
        // this only support 1 target, you can use array to support multiple target objects
        objc_setAssociatedObject(self, &AssociatedObjectHandle, wrapper, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
    }
}

希望在 SDK 的未来版本中,类似的方法采用闭包,而不是 Apple 会添加选择器,因此我们不需要自己实现它们。

【讨论】:

  • 那行不通,因为UIControl 不保留动作目标,所以它会在一个释放的实例上调用东西。
  • @bryanchen 这对我不起作用。我在文件顶部的 swift 代码上方包含了您的 sn-p。我确实添加了您使用 binderButton.addAction(forControlEvents: .TouchUpInside, withCallback: { abort() }) 描述的操作。它没有中止,断点没有命中。
  • 从 Swift 2.2 开始,这个答案现在不正确,其中 #selector 可用
【解决方案2】:

Swift 2.2 使用 #selector 语法对选择器进行编译时检查,请参阅 https://swift.org/blog/swift-2-2-new-features/Using Swift with Cocoa and Objective-C (Swift 2.2)

对于你的例子,它会这样写:

button.addTarget(self, selector: #selector(ViewController.buttonTapped(_:)), forControlEvents: .TouchUpInside)

【讨论】:

    【解决方案3】:

    这是我的 Swift 2.0 版本的 Bryan 的最佳答案:

    import UIKit
    
    public class CallbackHolder: NSObject {
    
        let callback: () -> Void
    
        init(callback: () -> Void) {
            self.callback = callback
        }
    
        public func call() {
            callback()
        }
    
    }
    
    private let AssociatedObjectHandle = UnsafePointer<Void>()
    
    extension UIButton {
    
        func addAction(forControlEvents events: UIControlEvents, withCallback callback: () -> Void) {
            let holder = CallbackHolder(callback: callback)
            addTarget(holder, action: "call", forControlEvents: events)
            objc_setAssociatedObject(self, AssociatedObjectHandle, holder, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) // prevent garbage collection
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-17
      • 1970-01-01
      • 2016-08-03
      • 2023-03-12
      • 2016-08-26
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      • 1970-01-01
      相关资源
      最近更新 更多