Sergio Bost
Sergio Bost

Reputation: 3209

How would I expose this function, that takes an enum as a parameter, to objc?

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?

Upvotes: 1

Views: 793

Answers (3)

Raja Kishan
Raja Kishan

Reputation: 18924

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)

Upvotes: 1

gnasher729
gnasher729

Reputation: 52538

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.

Upvotes: 0

Joakim Danielson
Joakim Danielson

Reputation: 51945

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

Upvotes: 1

Related Questions