Objective-C External constant property to Swift enum conversion

Viewed 146

I wanted to make an enum with the Contacts framework CNLabeledValue's CNPhoneNumber type which are defined as:

// Generic labels
CONTACTS_EXTERN NSString * const CNLabelHome    NS_AVAILABLE(10_11, 9_0);
CONTACTS_EXTERN NSString * const CNLabelWork    NS_AVAILABLE(10_11, 9_0);
CONTACTS_EXTERN NSString * const CNLabelSchool  NS_AVAILABLE(10_15, 13_0);
CONTACTS_EXTERN NSString * const CNLabelOther   NS_AVAILABLE(10_11, 9_0);

I did something like this:

enum CNLabeledValueType: String {
    case home
    case work
    case school
    case other

    var rawValue: String {
        switch self {
        case .home:
            return CNLabelHome
        case .work:
            return CNLabelHome
        case .school:
            return CNLabelSchool
        default:
            return CNLabelOther
        }
    }
}

But I think I still need to do some map the enum to the correct runtime strings, do I need to also override the init of the enum somehow?

What I would like to achieve would be the same result as if this would be possible:

enum CNLabeledValueType: String {
    case home = CNLabelHome
    case work = CNLabelWork
    case school = CNLabelSchool
    case other = CNLabelOther
}

But it is not possible because Swift enums require that "Raw value for enum must be a String literal" as the compiler complains. So is there any way to make something similar using computed properties to be possible to switch by case string and also get the correct string computed value at runtime for each case?

1 Answers

You can implement init(rawValue:) like this:

init?(rawValue: String) {
    switch rawValue {
    case CNLabelHome:
        self = .home
    case CNLabelWork:
        self = .work
    case CNLabelSchool:
        self = .school
    case CNLabelOther:
        self = .other
    default:
        return nil
    }
}

Also note that you have a typo in the rawValue implementation. The second case should return CNLabelWork. I also suggest not to use default: in the raw value switch statement:

var rawValue: String {
    switch self {
    case .home:
        return CNLabelHome
    case .work:
        return CNLabelWork
    case .school:
        return CNLabelSchool
    case .other:
        return CNLabelOther
    }
}

This way, when you want to add a new label, an error will appear at the switch statement, so you won't forget to add another case.

Related