Print Enum name of @objc Integer Enum

Have a objc compatible enum as

var str = "Hello, playground"


@objc public enum TestEnum:Int{

case String1

case String2

}


let testValue = TestEnum.String1


print( testValue) //prints TestEnum

print(String(describing: testValue)) //prints TestEnum


Is there a singleline statement that would print String1?

I could get it working only by defining another function in TestEnum to return String as below:


@objc public enum TestEnum:Int{

case String1

case String2

public var name:String{

get{

switch self {

case .String1:

return "String1"

default:

return "String2"

}

}}

}


print( testValue.name) //prints String1

Accepted Reply

Is there a singleline statement that would print String1?

No. Under the covers, C enums are represented by integer values; the C runtime does not have a copy of the string representation. For this to work in Swift, the Swift importer would have to generate these string representation and make them available to the Swift runtime. It does not do that, probably for good reasons [1].

Adding a conformance to

CustomStringConvertable
is one way to address this, but it’s not my preferred way. There’s a general guidance in Swift that you should not conform a type you don’t ‘own’ to a protocol you don’t define. That’s because there’s a potential for confusion if two subsystems within your process add conflicting conformances.

I generally solve this problem by adding a custom property to the enum to return the description I want. For example:

import CoreLocation

extension CLAuthorizationStatus {
    var debug: String {
        switch self {
        case .notDetermined: return "not determined"
        case .restricted: return "restricted"
        case .denied: return "denied"
        case .authorizedAlways: return "authorised always"
        @unknown default: return "unknown \(self.rawValue)"
        }
    }
}

let s = CLAuthorizationStatus.authorizedAlways
print(s.debug)

Note that this use a Swift 5 feature (

@unknown default
) to handle the ‘framework added a new case’ situation. See SE-0192 Handling Future Enum Cases for the details.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] I suspect that the main concerne here is the amount of space used by these strings. Apple’s SDKs contain a lot of enums.

Replies

It works in Swift


public enum TestEnum: Int {
    case String1
    case String2
}

let testValue = TestEnum.String1


print( testValue) //prints String1

print(String(describing: testValue)) //prints String1

yes, Swift enum works as expctec.

But need to have @objc Enum to support Xamarin platform.

Is there a way for objective C compatible Enum like above?

Interesting discussion here


https://stackoverflow.com/questions/24113126/how-to-get-the-name-of-enumeration-value-in-swift/31893968


But solution proposed should not work in Playground.


Quote:

"

Important catch, this only works for Swift enums. If you tag it @objc to allow binding support on OS X, this will not work. – Claus Jørgensen Feb 4 '16 at 23:17


Great Swift-specific answer; however, if you need to do this on a non-swift enum, such as to print the (Objective C) CLAuthorizationStatus enum's value inside your locationManager didChangeAuthorizationStatus delegate callback, you'd need to define a protocol extension. For example: extension CLAuthorizationStatus: CustomStringConvertable { public var description: String { switch self { case .AuthorizedAlways: return "AuthorizedAlways" <etc> } } } - once you've done this, it should work as you'd expect: print("Auth status: (\status))". – Jeffro Apr 27 '16 at 19:41

"

Is there a singleline statement that would print String1?

No. Under the covers, C enums are represented by integer values; the C runtime does not have a copy of the string representation. For this to work in Swift, the Swift importer would have to generate these string representation and make them available to the Swift runtime. It does not do that, probably for good reasons [1].

Adding a conformance to

CustomStringConvertable
is one way to address this, but it’s not my preferred way. There’s a general guidance in Swift that you should not conform a type you don’t ‘own’ to a protocol you don’t define. That’s because there’s a potential for confusion if two subsystems within your process add conflicting conformances.

I generally solve this problem by adding a custom property to the enum to return the description I want. For example:

import CoreLocation

extension CLAuthorizationStatus {
    var debug: String {
        switch self {
        case .notDetermined: return "not determined"
        case .restricted: return "restricted"
        case .denied: return "denied"
        case .authorizedAlways: return "authorised always"
        @unknown default: return "unknown \(self.rawValue)"
        }
    }
}

let s = CLAuthorizationStatus.authorizedAlways
print(s.debug)

Note that this use a Swift 5 feature (

@unknown default
) to handle the ‘framework added a new case’ situation. See SE-0192 Handling Future Enum Cases for the details.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] I suspect that the main concerne here is the amount of space used by these strings. Apple’s SDKs contain a lot of enums.

Great answer, I was going to add this code snippet I found as well:


bool enum3IsDefined = Enum.IsDefined(typeof(Color), 3);
bool enum4IsDefined = Enum.IsDefined(typeof(Color), 4);
//Results:
// enum3IsDefined = true
// enum4IsDefined = false


Snippet taken from: C# int to enum