Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I implement Default Associated Values with Swift Enums?

Tags:

enums

swift

Swift question is there a way of having an enum type with one case that can have an associated value.

I have an API that gives me available filters, it's unlikely but possible that the API will add additional filter types. So if the API sends an unknown filter type I want to keep that information associated with the enum.

Below are the different ideas I had about doing this.

My first two tries didn't compile. My third try just feels a bit clunky.

Does anyone have a better way of doing this? Do you think I just shouldn't use an enum for this problem?

typealias APIFilterIdentifier = String

/* Does Not Compile */
enum EnumTestAssociatedValeu: APIFilterIdentifier {
    case Unknown(APIFilterIdentifier)
    case Everyone = "everyone"
    case Team = "myteam"
}

/* Does not compile */
enum EnumTestDefaultAssociatedValues: APIFilterIdentifier {
    case Unknown(APIFilterIdentifier)
    case Everyone(APIFilterIdentifier = "everyone")
    case Team(APIFilterIdentifier = "myteam")
}

/* Compiles but is there a better way? */
enum EnumTestWithCustomInit {

    case Unknown(APIFilterIdentifier)
    case Everyone
    case Team

    init(filterIdentifier: APIFilterIdentifier) {
        let everyone: APIFilterIdentifier = EnumTestWithCustomInit.everyoneFilterIdentifier
        let team: APIFilterIdentifier = EnumTestWithCustomInit.teamFilterIdentifier

        switch filterIdentifier {
        case everyone:
            self = .Everyone
        case team:
            self = .Team
        default:
            self = .Unknown(filterIdentifier)
        }
    }

    func asIdentifer() -> APIFilterIdentifier {
        switch self {
        case .Everyone:
            return EnumTestWithCustomInit.everyoneFilterIdentifier
        case .Team:
            return EnumTestWithCustomInit.teamFilterIdentifier
        case .Unknown(let filterIdentifier):
            return filterIdentifier
        }
    }

    private static var everyoneFilterIdentifier: APIFilterIdentifier {
        return "everyone"
    }

    private static var teamFilterIdentifier: APIFilterIdentifier {
        return "myteam"
    }
}
like image 555
Tobias Avatar asked Apr 22 '15 19:04

Tobias


People also ask

Can an enum have a default value?

Rule descriptionThe default value of an uninitialized enumeration, just like other value types, is zero. A non-flags-attributed enumeration should define a member that has the value of zero so that the default value is a valid value of the enumeration.

What is associated value in enum Swift?

This additional information is called an associated value, and it varies each time you use that case as a value in your code. You can define Swift enumerations to store associated values of any given type, and the value types can be different for each case of the enumeration if needed.

Why Swift enums with associated values Cannot have a raw value?

A Swift enum can either have raw values or associated values. Why is that? It's because of the definition of a raw value: A raw value is something that uniquely identifies a value of a particular type. “Uniquely” means that you don't lose any information by using the raw value instead of the original value.

Can you give useful examples of enum associated values?

These additional information attached to enum values are called associated values. Let's see an example, enum Distance { // associate value case km(String) ... } Here, (String) is additional information attached to the value km .


2 Answers

I know this is a bit old, but would this work for what you want?

typealias FilterIdentifier = String

enum DefaultAPIFilters: FilterIdentifier {
    case Everyone = "everyone"
    case Team = "team"
}

enum APIFilters {
    case Default(DefaultAPIFilters)
    case Custom(FilterIdentifier)
}

let everyoneFilter = APIFilters.Default(.Everyone)
let teamFilter = APIFilters.Default(.Team)
let clownFilter = APIFilters.Custom("clowns_only")
like image 121
Nathan Perry Avatar answered Sep 21 '22 18:09

Nathan Perry


Extending Nathan Perry's response:

You can add a

var underlyingString: String {
  return getUnderlyingString(self) 
}

to the enum. Then define

func getUnderlyingString(apiFilter: APIFilters) -> String { 
    switch apiFilter {
    case .Default(let defaultAPIFilter):
        return defaultAPIFilter.rawValue
    case .Custom(let custom):
        return custom
    }
}
like image 41
SG1 Avatar answered Sep 22 '22 18:09

SG1