1

So I'm defining an objc method:

 @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")
    }
}

That I would like to call here:

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

Is it possible to pass enums as a parameter to objc?

Sergio Bost
  • 2,591
  • 2
  • 11
  • 29

3 Answers3

1

You can make use of a enum raw value instead in this case.

Change the enum to have raw values, like an Int for example

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

Then change the signature of the method to take that raw value instead and inside the function you can convert it to an enum item

@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)")
    }
}

This fixes the @objc related error but note that you can not pass a custom argument when using #selector

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
  • Thanks, I got rid of the first error, now at the call site: `postButton.addTarget(self, action: #selector(networkCall(action: "POST")), for: .touchUpInside)` the error is `Argument of '#selector' does not refer to an '@objc' method, property, or initializer` Im thinking I need to use objc syntax here? – Sergio Bost Jul 03 '21 at 13:52
  • 1
    See the last sentence of my answer – Joakim Danielson Jul 03 '21 at 14:06
1

You can fix your @objc error from this link.

But you still face the problem for passing value to the parameter.

You can use the subclass of the UIButton.

Here is the demo

Custom Button Class

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

Target Method

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

Usage

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


Another approach you can use the tag.

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)

from iOS14

You can simply use the addAction instead of the target.

button.addAction(UIAction(handler: { [weak self] action in
    self?.networkCall(sender: .post)
}), for: .touchUpInside)
Raja Kishan
  • 16,767
  • 2
  • 26
  • 52
0

You can move the enum itself into an Objective-C header file. Swift can use Objective-C enum without problems, but obviously without Swift features. That’s obviously unpleasant, so if possible you would convert the caller to Swift and move the enum back to the Swift file where it belongs.

gnasher729
  • 51,477
  • 5
  • 75
  • 98