Raw Value of Enumeration, Default Value of a Class/Structure, What's the Different

Raw Value of Enumeration, Default value of a class/structure, What's the different?

From Apple docs:

Raw Values

The barcode example in Associated Values shows how cases of an
enumeration can declare that they store associated values of different
types. As an alternative to associated values, enumeration cases can
come prepopulated with default values (called raw values), which are
all of the same type.

So I guess it is the same.

On the other hand, with "default value", you may be referring to the default value of an enum case where no values have been set, for example:

enum TestEnum: Int  {    
case A
case B
}

Here, TestEnum.A has a default value of 0, and TestEnum.B has a default value of 1.

Raw value refers to the actual value of an enum case (in the enum's type, in this example it would be Int):

enum TestEnum: Int  {    
case A
case B = 3
}

Here, TestEnum.A has the default value (which is also the raw value) of 0, and TestEnum.B has a raw value of 3 (which is no longer the default value).

Difference between associated and raw values in swift enumerations

Raw values are for when every case in the enumeration is represented by a compile-time-set value. The are akin to constants, i.e.

let A = 0
let B = 1

is similar to:

enum E: Int {
case A // if you don't specify, IntegerLiteralConvertible-based enums start at 0
case B
}

So, A has a fixed raw value of 0, B of 1 etc set at compile time. They all have to be the same type (the type of the raw value is for the whole enum, not each individual case). They can only be literal-convertible strings, characters or numbers. And they all have to be distinct (no two enums can have the same raw value).

Associated values are more like variables, associated with one of the enumeration cases:

enum E {
case A(Int)
case B
case C(String)
}

Here, A now has an associated Int that can hold any integer value. B on the other hand, has no associated value. And C has an associated String. Associated types can be of any type, not just strings or numbers.

Any given value of type E will only ever hold one of the associated types, i.e. either an Int if the enum is an A, or a String if the enum is a C. It only needs enough space for the bigger of the two. Types like this are sometimes referred to as "discriminated unions" – a union being a variable that can hold multiple different types, but you know (from the enum case) which one it is holding.

They can even be generic. The most common example of which is Optional, which is defined like this:

enum Optional<T> {
case .Some(T)
case .None
}

Swift enum cannot assign default raw value

In (Objective-)C an enumeration defines a set of named integer constants, and those need not be distinct:

enum {
A = 1,
B = 2,
C = 99,
Default = B
};

The cases of a Swift enum represent mutually distinct values, and their raw values – if assigned – must be unique:

enum BestLetters: Int {
case a = 1
case b
case c
case `default` = 2 // Error: Raw value for enum case is not unique
}

On the other hand, enumerations in Swift are first-class types, so that you can define a static property for that purpose:

enum BestLetters {
case a
case b
case c
static let `default` = BestLetters.b
}

(This is also how Swift imports C enumerations with duplicate values, compare touchIDLockout deprecated in iOS 11.0.)

Codable enum with default case in Swift 4

You can extend your Codable Type and assign a default value in case of failure:

enum Type: String {
case text,
image,
document,
profile,
sign,
inputDate = "input_date",
inputText = "input_text" ,
inputNumber = "input_number",
inputOption = "input_option",
unknown
}
extension Type: Codable {
public init(from decoder: Decoder) throws {
self = try Type(rawValue: decoder.singleValueContainer().decode(RawValue.self)) ?? .unknown
}
}

edit/update:

Xcode 11.2 • Swift 5.1 or later

Create a protocol that defaults to last case of a CaseIterable & Decodable enumeration:

protocol CaseIterableDefaultsLast: Decodable & CaseIterable & RawRepresentable
where RawValue: Decodable, AllCases: BidirectionalCollection { }

extension CaseIterableDefaultsLast {
init(from decoder: Decoder) throws {
self = try Self(rawValue: decoder.singleValueContainer().decode(RawValue.self)) ?? Self.allCases.last!
}
}

Playground testing:

enum Type: String, CaseIterableDefaultsLast {
case text, image, document, profile, sign, inputDate = "input_date", inputText = "input_text" , inputNumber = "input_number", inputOption = "input_option", unknown
}

let types = try! JSONDecoder().decode([Type].self , from: Data(#"["text","image","sound"]"#.utf8))  // [text, image, unknown]

How to get enum from raw value in Swift?

Too complicated, just assign the raw values directly to the cases

enum TestEnum: String {
case Name = "Name"
case Gender = "Gender"
case Birth = "Birth Day"
}

let name = TestEnum(rawValue: "Name")! //Name
let gender = TestEnum(rawValue: "Gender")! //Gender
let birth = TestEnum(rawValue: "Birth Day")! //Birth

If the case name matches the raw value you can even omit it

enum TestEnum: String {
case Name, Gender, Birth = "Birth Day"
}

In Swift 3+ all enum cases are lowercased

How to get enum value of raw type from an enum class and a string in kotlin

Here's a pure Kotlin version:

@Suppress("UNCHECKED_CAST")
fun getEnumValue(enumClass: Class<*>, value: String): Enum<*> {
val enumConstants = enumClass.enumConstants as Array<out Enum<*>>
return enumConstants.first { it.name == value }
}

Note that it's not as efficient as the Java version. java.lang.Enum.valueOf uses a cached data structure while this version needs to create a new array to iterate over. Also this version is O(n) wheras the Java version is O(1) as it uses a dictionary under the hood.

There is an open issue in the Kotlin bug tracker to support the same code as in Java which is scheduled for 1.3.

Here's a really ugly hack to workaround the generic type issue:

private enum class Hack

fun getEnumValue(enumClass: Class<*>, value: String): Enum<*> {
return helper<Hack>(enumClass, value)
}

private fun <T : Enum<T>>helper(enumClass: Class<*>, value: String): Enum<*> {
return java.lang.Enum.valueOf(enumClass as Class<T>, value)
}

A quick test shows that it's working but I wouldn't rely on it.


If the generic type is available, you can use the built-in function enumValueOf (see also http://kotlinlang.org/docs/reference/enum-classes.html#working-with-enum-constants):

enum class Color {
Red, Green, Blue
}

enumValueOf<Color>("Red")

Swift enum with custom initializer loses rawValue initializer

This bug is solved in Xcode 7 and Swift 2

How to get the name of enumeration value in Swift?

As of Xcode 7 beta 5 (Swift version 2) you can now print type names and enum cases by default using print(_:), or convert to String using String's init(_:) initializer or string interpolation syntax. So for your example:

enum City: Int {
case Melbourne = 1, Chelyabinsk, Bursa
}
let city = City.Melbourne

print(city)
// prints "Melbourne"

let cityName = "\(city)" // or `let cityName = String(city)`
// cityName contains "Melbourne"

So there is no longer a need to define & maintain a convenience function that switches on each case to return a string literal. In addition, this works automatically for any enum, even if no raw-value type is specified.

debugPrint(_:) & String(reflecting:) can be used for a fully-qualified name:

debugPrint(city)
// prints "App.City.Melbourne" (or similar, depending on the full scope)

let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"

Note that you can customise what is printed in each of these scenarios:

extension City: CustomStringConvertible {
var description: String {
return "City \(rawValue)"
}
}

print(city)
// prints "City 1"

extension City: CustomDebugStringConvertible {
var debugDescription: String {
return "City (rawValue: \(rawValue))"
}
}

debugPrint(city)
// prints "City (rawValue: 1)"

(I haven't found a way to call into this "default" value, for example, to print "The city is Melbourne" without resorting back to a switch statement. Using \(self) in the implementation of description/debugDescription causes an infinite recursion.)


The comments above String's init(_:) & init(reflecting:) initializers describe exactly what is printed, depending on what the reflected type conforms to:

extension String {
/// Initialize `self` with the textual representation of `instance`.
///
/// * If `T` conforms to `Streamable`, the result is obtained by
/// calling `instance.writeTo(s)` on an empty string s.
/// * Otherwise, if `T` conforms to `CustomStringConvertible`, the
/// result is `instance`'s `description`
/// * Otherwise, if `T` conforms to `CustomDebugStringConvertible`,
/// the result is `instance`'s `debugDescription`
/// * Otherwise, an unspecified result is supplied automatically by
/// the Swift standard library.
///
/// - SeeAlso: `String.init<T>(reflecting: T)`
public init<T>(_ instance: T)

/// Initialize `self` with a detailed textual representation of
/// `subject`, suitable for debugging.
///
/// * If `T` conforms to `CustomDebugStringConvertible`, the result
/// is `subject`'s `debugDescription`.
///
/// * Otherwise, if `T` conforms to `CustomStringConvertible`, the result
/// is `subject`'s `description`.
///
/// * Otherwise, if `T` conforms to `Streamable`, the result is
/// obtained by calling `subject.writeTo(s)` on an empty string s.
///
/// * Otherwise, an unspecified result is supplied automatically by
/// the Swift standard library.
///
/// - SeeAlso: `String.init<T>(T)`
public init<T>(reflecting subject: T)
}


See the release notes for info about this change.



Related Topics



Leave a reply



Submit