DookieMan
DookieMan

Reputation: 1044

How to access passed Enum argument in Swift 3

I'm having some trouble accessing a parameter that is passed with an enum.

Generic RequestType, more will be included.

enum RequestType {
  case flagging(api : FlaggingRequestType)
}

Here is my enum that accepts another FlaggingRequestType (another enum that accepts a string parameter)

enum FlaggingRequestType {
  case getFlag(api : String)
}

protocol Requestable {
  var requestType : RequestType { get set }
}

Here I build my flagging request

let flaggingRequest = RequestBuilder.buildFlaggingRequest(flagRequest: .getFlag(api: "http://www.apiworld.com"))

Here is my method to actually sends the request from another method.

func sendRequest(for apiRequest : Requestable) {
  switch apiRequest.requestType {
  case .flagging:
  self.flaggingAPI(for: apiRequest)
 }
}

The problem is I can't figure out how to access the value passed in the api parameter found in apiRequest/ flaggingRequest. Is this possible? I hope this is clear :)

Upvotes: 20

Views: 34696

Answers (4)

Frederik
Frederik

Reputation: 414

Since it is nested, you will have to do nested switch cases, like this:

switch apiRequest {
case .flagging(let value):
    switch value {
    case .getFlag(let api):
        print(api) // api is the string passed in the associated value
        break
    }
    break
}

UPDATE

Swift has changed the behaviour around switch statements, so cases are no longer falling through to the next case. This means you no longer need to explicitly break. Instead, if you want the old behaviour, you can use the fallthrough keyword, to make your execution continue into the next case.

You can also unwrap cases in the outer switch:

switch apiRequest {
case .flagging(.getFlag(let api)):
    print(api) // api is the string passed in the associated value
}

Upvotes: 6

Riswan Ardiansah
Riswan Ardiansah

Reputation: 1

In Swift UI

enum Action {
case INCREMENT
case DECREMENT
}

struct ContentView: View {
    @State var counter = 0
    var body: some View {
        HStack {
            Button(action: {
                handleIncreaseDecrease(action: Action.DECREMENT)
            }) {
                Text("-")
            }
            Text("\(counter)")
            Button(action: {
                handleIncreaseDecrease(action: Action.INCREMENT)
            }) {
                Text("+")
            }
        }
    }
    
func handleIncreaseDecrease(action:Action) {
    if (action == Action.INCREMENT) {
        counter += 1
    } else {
        counter -= 1
    }
}
}

Upvotes: -1

dfrib
dfrib

Reputation: 73206

"Nested" pattern matching & value binding: case .one(.two(let val))

If, for a given instance of a type that conforms to Requestable, your single goal is to access the associated String value of the "inner" FlaggingRequestType instance (for a known inner case), you can use nested pattern matching and binding in a single case, e.g. used not only in a switch buy, say, an if statement.

// your example setup
enum FlaggingRequestType {
    case getFlag(api : String)
}

protocol Requestable {
    var requestType : RequestType { get set }
}

enum RequestType {
    case flagging(api : FlaggingRequestType)
}
    
// dummy type conforming to 'Requestable'
struct Foo : Requestable {
    var requestType: RequestType =
        .flagging(api: .getFlag(api: "http://www.apiworld.com"))
}

// Q: how to find the nested "http://www.apiworld.com" String
//    from a 'Foo' instance?
let foo = Foo()

// A: use nested pattern matching, e.g. in a single 'if' statement
if case .flagging(.getFlag(let api)) = foo.requestType {
    print(api) // http://www.apiworld.com
}

You can naturally make use of the nested pattern matching also in the cases of a switch statement:

switch foo.requestType {
case .flagging(.getFlag(let api)): print(api) // http://www.apiworld.com
// ...
default : () // in non-exhaustive pattern matching above
}

In case the associated value of different types of the FlaggingRequestType are of the same type, and also the same expected usage, this nested binding can be a useful alternative to several nested switch statements. E.g., if extending the example setup above to:

enum FlaggingRequestType {
    case getFlag(api : String)
    case getHandle(api : String)
    case getId(id: Int)
}

We could apply nested pattern matching in a single switch statement, where one single case could cover binding associated values for several different cases of the inner enum, given that those associated values have the same type.

switch foo.requestType {
case .flagging(.getFlag(let api)),
     .flagging(.getHandle(let api)): print(api) // api is 'String', a flag or a handle
case .flagging(.getId(let id)):      print(id)  // id is 'Int'
// ...
default : () // in case of non-exhaustive pattern matching above
}

Finally, note that you might want to consider using type constrained generics for your sendRequest method, rather than typing out a protocol to be used as type.

func sendRequest<T: Requestable>(for apiRequest : T) { /* ... */ }

Upvotes: 8

dmorrow
dmorrow

Reputation: 5694

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

Upvotes: 29

Related Questions