Possible to Pass an Enum Type Name as an Argument in Swift

Possible to pass an enum type name as an argument in Swift?

You can take advantage of the fact that enums with raw values automatically conform to the RawRepresentable protocol. You can define a generic function that takes a metatype argument of a given type T (spelled as T.Type), where that T is RawRepresentable and, also in your case, its RawValue is Int.

This will allow you to pass in the metatypes of both Foo and Bar, spelled Foo.self and Bar.self respectively:

func justAnExample<T : RawRepresentable>(_ enumType: T.Type) where T.RawValue == Int {

// Note that an explicit use of init is required when creating an instance from a
// metatype. We're also using a guard, as `init?(rawValue:)` is failable.
guard let val = enumType.init(rawValue: 0) else { return }
print("description: \(val)")
}

justAnExample(Foo.self) // prints: "description: Hello Foo"
justAnExample(Bar.self) // prints: "description: Hello Bar"

Passing various enum case as function param in Swift

The linked question is actually quite close - you just have to change the parameter type to just T, instead of T.Type:

func printCase<T : RawRepresentable>(_ e: T) where T.RawValue == String {
print(e.rawValue)
}

Since you are accepting an instance of the enum, not the enum type itself.

Of course, you don't have to restrict this to enums where T.RawValue == String, since print can print Anything.

Use enum as a function parameter

That's a warning not an error. It's simply saying that the result of the call to numeroMes is not used.

Incidentally, it looks like you can use a raw type for the enumeration instead of defining a custom conversion function. Here's how

enum Mese: Int {
case Enero = 1
case Febrero
case Marzo
case Abril
case Mayo
case Junio
case Julio
case Agosto
case Septiembre
case Octubre
case Noviembre
case Diciembre
}

The other values will increment from 1, so Febrero is 2, Marzo is 3 and so on.

Now whenever you need to retrieve the raw value from an enum, just call rawValue on it. Example:

Mese.Febrero.rawValue // 2

Can a function argument's type be a specific enum 'case'?

You can only pass an Enum as a parameter, not its cases. So you can either write that function like this -

enum MyTimer {
case describe(userId: String,
endTime: Int)
case vote(endTime: Int)
}


func onDescribeTimerChange(timer: MyTimer) {
switch timer {
case let .describe(userId, endTime):
print(userId, endTime)
case .vote(let endTime):
print(endTime)
}
}


onDescribeTimerChange(timer: .describe(userId: "userID", endTime: 2))

Or you can use that as a method associated with your MyTimer enum type, like this -

enum MyTimer {
case describe(userId: String,
endTime: Int)
case vote(endTime: Int)

func onDescribeTimerChange() {
switch self {
case let .describe(userId, endTime):
print(userId, endTime)
case .vote(let endTime):
print(endTime)
}
}
}


MyTimer.describe(userId: "userID", endTime: 1).onDescribeTimerChange()

How to access passed Enum argument in Swift 3

Here's a great link for enums with associated values https://appventure.me/2015/10/17/advanced-practical-enum-examples/#sec-1-5

func sendRequest(for apiRequest : Requestable) {
switch apiRequest.requestType {
case .flagging(let api):
// access api value here
self.flaggingAPI(for: apiRequest)
}
}

How to pass an enum case into a function that uses 'if case' to check for a property's case

The answer of Shadowrun is a good start. Through the CasePaths library I found EnumKit, which was partially the inspiration for CasePaths. However it gives much simpler methods to compare cases. See my implementation below.

Using this library comes with some nice bonuses, it allows enums that have associated values to be made equatable by just comparing the cases and ignoring the values. This might not always be desired but come in quite handy in a lot of cases. I use it to compare ReSwift Actions with Associated values in my tests.

import Foundation
import EnumKit

class NonEquatableObject {
}

enum MyEnum: CaseAccessible { // <-- conform to CaseAccessible
case justACase
case numberCase(Int)
case stringCase(String)
case objectCase(NonEquatableObject)
}

let myArray: [MyEnum] = [.justACase, .numberCase(100), .stringCase("Hello Enum"), .justACase]

if case .justACase = myArray[0] {
print("myArray[0] is .justACase")
}

if case .numberCase = myArray[1] {
print("myArray[1] is .numberCase")
}


func checkCase(lhsCase: MyEnum, rhsCase: MyEnum) -> Bool {
if case lhsCase = rhsCase {
return true
} else {
return false
}
}

// Usage:
if checkCase(lhsCase: .justACase, rhsCase: myArray[0]) { //<-- allows to pass variables or just the cases (unfortunately not without associated value.)
print("myArray[0] is .justACase")
}

if case myArray[3] = myArray[0] { //<-- allows this here too
print("myArray[0] is .justACase")
}

// Bonus: Adding equatable if associated values are not equatable. Looking at the case only.
extension MyEnum: Equatable {
static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
lhs.matches(case: rhs)
}
}

if myArray[3] == myArray[0] {
print("myArray[3] == myArray[0]")
}

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

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)


Related Topics



Leave a reply



Submit