【问题标题】:Proper way to use selectors in Swift在 Swift 中使用选择器的正确方法
【发布时间】:2016-04-14 16:18:59
【问题描述】:

我正在以编程方式创建一个视图,并添加一个函数,以便该操作响应 UIControlEvents.TouchUpInside 事件:

button.addTarget(self, action: action, forControlEvents: 
UIControlEvents.TouchUpInside)

因此,通过查看文档,我已将此操作添加为选择器:

#selector(ViewController.onRegularClick)

XCode 然后抱怨:

#selector 的参数指的是不暴露于 目标-C

所以我必须设置处理函数:

@objc func onRegularClick(sender: UIButton)

有人可以通过指导我查看文档来把这个菜鸟放在正确的方向上,或者甚至给出一个简短的解释,关于:

  1. 为什么我不能再简单地将函数名称字符串传递给操作?
  2. 遵循 Swift 方式的正确方法是什么?使用 Selector 类?
  3. 为什么我们需要传递@objc 关键字以及它如何影响函数?

谢谢!

【问题讨论】:

标签: ios swift selector


【解决方案1】:
  1. 为什么我不能再简单地将函数名称字符串传递给操作?

不推荐使用字符串作为选择器,您现在应该写#selector(methodName)而不是"methodName"。如果methodName() 方法不存在,您将得到一个编译错误——在编译时消除了另一整类错误。这在字符串中是不可能的。

  1. 遵循 Swift 方式的正确方法是什么?使用 Selector 类?

你做对了:

button.addTarget(self, action: #selector(ClassName.methodName(_:)), forControlEvents: UIControlEvents.TouchUpInside)

  1. 为什么我们需要传递@objc 关键字以及它如何影响函数?

在 Swift 中,通常的方法是在编译时绑定方法的调用和方法的主体(就像 C 和 C++ 一样)。 Objective C 在运行时执行它。所以在 Objective C 中你可以做一些 Swift 做不到的事情——例如可以在运行时交换方法的实现(它被称为方法调配)。 Cocoa 旨在与 Objective C 方法一起使用,这就是为什么您必须告知编译器您的 Swift 方法应该以类似 Objective-C 的样式编译的原因。如果你的类继承了 NSObject,即使没有 @objc 关键字,它也会被编译成类似 ObjC 的风格。

【讨论】:

  • 即使在 Swift 4.1 中,您仍然可以从字符串创建选择器。 let selector = Selector.init("lalalal")
  • NSSelectorFromString("selectorName:arg:")
【解决方案2】:
  1. 嗯,这叫进化
  2. 当方法中有一些参数时,你应该将选择器声明为:

    let selector = #selector(YourClass.selector(_:))
    

    如果选择器与调用者在同一类中,则只能键入 #selector(selector(_:))_: 表示接受一个参数。所以,如果它接受更多的参数,你应该这样做:(_:, _:)等等。

  3. 我发现@objc只有在函数声明为私有或对象不继承自NSObject时才需要

【讨论】:

  • 如果您的班级不在NSObject 层次结构中,我敢想象还需要@objc?诚然,这种情况很少见,因为您很可能会收到 UI 反馈,因此您是 UIViewController 的后代。
  • 不知道私有函数可以是带有objc属性的选择器!万分感谢! +1
【解决方案3】:

1:目前可以,但会产生不推荐使用的警告。在斯威夫特 3 这将是一个错误,因此您应该尽快修复它。这个做完了 因为编译器无法检查仅使用字符串 if 该函数确实存在,如果它是一个有效的 Objective C 函数 可以在运行时动态解决。

2:这样做:

button.addTarget(self, action: #selector(MyViewControllerClass.buttonPressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)

3:通常您不必使用@objc 属性。我假设您的课程ViewController(出于任何原因)不是从UIViewController 派生的。如果它派生自UIViewController,则还继承了调用函数选择器所需的 ObjC 行为。

【讨论】:

    【解决方案4】:

    对于 swift3.0 只需执行以下代码:

            yourButton.addTarget(self, action: #selector(yourButtonPressed), for: .touchUpInside)
    

    和 yourButtonPressed 方法

    @IBAction func yourButtonPressed(sender:UIButton) {
        // Do your code here
    }
    

    【讨论】:

      【解决方案5】:

      每个人的答案都很完美,但我有更好的方法。希望你会喜欢。

      fileprivate extension Selector {
          static let buttonTapped = 
              #selector(ViewController.buttonTapped(_:))
      }
      ...
      button.addTarget(self, action: .buttonTapped, for: .touchUpInside)
      

      在此文件中,private 将有助于仅在文件中显示 buttonTapped。

      【讨论】:

        【解决方案6】:

        以编程方式

        button.addTarget(self, action: #selector(returnAction), for: .touchUpInside)
        
        // MARK: - Action
        @objc private func returnAction(sender: UIButton) {
            print(sender.tag)            
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多