23

I’m trying to log an enum:

enum CKAccountStatus : Int {
    case CouldNotDetermine
    case Available
    case Restricted
    case NoAccount
}

NSLog("%i", CKAccountStatus.Available)

The compiler complains:

Type 'CKAccountStatus' does not conform to protocol 'CVarArg'

Why? I have tried to cast the value:

NSLog("%i", CKAccountStatus.Available as Int)

But that doesn’t fly either:

Cannot convert the expression's type '()' to type 'String'
zoul
  • 102,279
  • 44
  • 260
  • 354

7 Answers7

30

Get the enum's underlying Int value:CKAccountStatus.Available.rawValue.

Enums are not strictly integers in Swift, but if they're declared with an underlying type you can get it with rawValue — whatever that underlying type is. (enum Foo: String will give you strings for the rawValue, etc.) If an enum doesn't have an underlying type, rawValue has nothing to give you. In APIs imported from ObjC, any enum defined with NS_ENUM has an underlying integer type (typically Int).

If you'd like to print any enum more descriptively, you might consider making an extension on the enum type that adopts the Printable protocol.

rickster
  • 124,678
  • 26
  • 272
  • 326
  • 1
    I have found for simple `Int` enums, `.hashValue` will also give you access to the `Int` value. – tfrank377 Nov 05 '14 at 17:53
  • 2
    Using `hashValue` would be abuse of the API contract. A `Hashable` type requires that `hashValue` be identical for "equal" values and unique otherwise, but makes no other guarantees... even if it coincidentally returns the same as `rawValue` for an `Int` enum type, you don't know that won't change in the future. It's always best to choose the API that's documented to do what you want over the one that happens to do what you want. – rickster Nov 05 '14 at 20:39
8

An enum is effectively opaque. It might have raw values, which you can get; but many enums don't. (You don't have to declare the enum as having a type, and if you don't, there are no raw values.) What I would do is give the enum a description method and call it explicitly.

The only way to distinguish the enum's current value is through a switch statement, so your description method will handle each case, and each case of the switch statement will return a different descriptive value.

enum Suit {
    case Hearts, Diamonds, Spades, Clubs
    func description () -> String {
        switch self {
        case Hearts:
            return "hearts"
        case Diamonds:
            return "diamonds"
        case Spades:
            return "spades"
        case Clubs:
            return "clubs"
        }
    }
}

var suit = Suit.Diamonds
println("suit \(suit.description())")  // suit diamonds
idmean
  • 14,540
  • 9
  • 54
  • 83
matt
  • 515,959
  • 87
  • 875
  • 1,141
5

This is my approach:

enum UserMode : String
{
   case Hold = "Hold";
   case Selecting = "Selecting";
   case Dragging = "Dragging";
}

Then, whenever I need to print the raw value:

//Assuming I have this declared and set somewhere
var currentMode: UserMode = .Selecting;

Doing

NSLog("CurrentMode \(_currMode.rawValue)");

Will print:

CurrentMode Selecting

Chris Amelinckx
  • 4,334
  • 2
  • 23
  • 21
1

From the Swift docs:

If you are familiar with C, you will know that C enumerations assign related names to a set of integer values. Enumerations in Swift are much more flexible, and do not have to provide a value for each member of the enumeration. If a value (known as a “raw” value) is provided for each enumeration member, the value can be a string, a character, or a value of any integer or floating-point type.

Therefore you cannot try to cast it to and Int. As far as your first problem it seems that NSLog() is looking for a parameter of type C-variable, which does not apply to Swift enums.

67cherries
  • 6,931
  • 7
  • 35
  • 51
0

I see, enums are not numbers in Swift:

Unlike C and Objective-C, Swift enumeration members are not assigned a default integer value when they are created. In the CompassPoints example above, North, South, East and West do not implicitly equal 0, 1, 2 and 3. Instead, the different enumeration members are fully-fledged values in their own right, with an explicitly-defined type of CompassPoint.

Is there a way to easily log the value, then? Ah, there is:

NSLog("%i", CKAccountStatus.Available.toRaw())
zoul
  • 102,279
  • 44
  • 260
  • 354
0

You can use the toRaw() function to get the Int-Value of the enum like follows:

import Foundation

enum CKAccountStatus : Int {
    case CouldNotDetermine
    case Available
    case Restricted
    case NoAccount
}

let block = {(status: Int) -> Void in
    NSLog("%d", status)
}

let status = CKAccountStatus.Available.toRaw()
block(status) // prints "1"
Dennis Zoma
  • 2,621
  • 2
  • 17
  • 27
0

For my Error enums I use

public var localizedDescription : String { return String(reflecting: self) }

for other enums there is the CustomStringConvertible protocol that can be used as

public var description : String { return String(reflecting: self) }
JMiguel
  • 1,459
  • 1
  • 10
  • 12