【问题标题】:How would I expose this function, that takes an enum as a parameter, to objc?我如何将这个以枚举作为参数的函数公开给 objc?
【发布时间】:2021-07-03 13:33:25
【问题描述】:

所以我定义了一个 objc 方法:

 @objc func networkCall(action: NetworkAction) { //Error: Method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C
    switch action {
    case .post:
        print("Posting")
    case .get:
        print("Getting")
    case .delete:
        print("Deleting")
    case .update:
        print("Updating")
    }
}

我想在这里打电话:

 postButton.addTarget(self, action: #selector(networkCall(action: .post)), for: .touchUpInside) //Error: Argument of '#selector' does not refer to an '@objc' method, property, or initializer

是否可以将枚举作为参数传递给 objc?

【问题讨论】:

    标签: swift


    【解决方案1】:

    您可以从此link 修复您的@objc 错误。

    但是您仍然面临将值传递给参数的问题。

    您可以使用 UIButton 的子类。

    这里是演示

    自定义按钮类

    class CustomButton: UIButton {
        var networkAction: NetworkAction = .post
    }
    

    目标方法

    @objc func networkCall(sender: CustomButton) {
            switch sender.networkAction {
            case .post:
                print("Posting")
            case .get:
                print("Getting")
            case .delete:
                print("Deleting")
            case .update:
                print("Updating")
            }
        }
    

    用法

    let postButton = CustomButton()
    postButton.networkAction = .post
    postButton.addTarget(self, action: #selector(networkCall(sender:)), for: .touchUpInside)
    


    您可以使用标签的另一种方法。

    enum NetworkAction: Int {
        case post = 0
        case get = 1
        case delete = 2
        case update = 3
    }
    
    @objc func networkCall(sender: UIButton) {
            switch NetworkAction(rawValue: sender.tag) {
            case .post:
                print("Posting")
            case .get:
                print("Getting")
            case .delete:
                print("Deleting")
            case .update:
                print("Updating")
            case .none:
                print("none")
            }
        }
    
    let postButton = UIButton()
    postButton.tag = 0
    postButton.addTarget(self, action: #selector(networkCall(sender:)), for: .touchUpInside)
    
    

    来自 iOS14

    您可以简单地使用addAction 代替目标。

    button.addAction(UIAction(handler: { [weak self] action in
        self?.networkCall(sender: .post)
    }), for: .touchUpInside)
    

    【讨论】:

      【解决方案2】:

      在这种情况下,您可以改用枚举原始值。

      将枚举更改为具有原始值,例如 Int

      enum NetworkAction: Int {
          case post
          case get
          case delete
          case update
      }
      

      然后更改方法的签名以取而代之的是原始值,并在函数内部将其转换为枚举项

      @objc func networkCall(action: NetworkAction.RawValue) {
          let enumAction = NetworkAction(rawValue: action)
          switch enumAction {
          case .post:
              print("Posting")
          case .get:
              print("Getting")
          case .delete:
              print("Deleting")
          case .update:
              print("Updating")
          case .none: //If the above init(rawValue:) returned nil
              fatalError("Unknow raw value sent: \(action)")
          }
      }
      

      这修复了与@objc 相关的错误,但请注意,使用#selector 时不能传递自定义参数

      【讨论】:

      • 谢谢,我摆脱了第一个错误,现在在调用站点:postButton.addTarget(self, action: #selector(networkCall(action: "POST")), for: .touchUpInside) 错误是Argument of '#selector' does not refer to an '@objc' method, property, or initializer 我想我需要在这里使用 objc 语法?
      • 看我回答的最后一句话
      【解决方案3】:

      您可以将枚举本身移动到 Objective-C 头文件中。 Swift 可以毫无问题地使用 Objective-C 枚举,但显然没有 Swift 特性。这显然令人不快,所以如果可能的话,你会将调用者转换为 Swift 并将枚举移回它所属的 Swift 文件中。

      【讨论】:

        猜你喜欢
        • 2011-12-04
        • 2011-05-30
        • 1970-01-01
        • 2014-02-10
        • 2020-06-09
        • 1970-01-01
        • 1970-01-01
        • 2020-09-25
        • 1970-01-01
        相关资源
        最近更新 更多