Why is an Enum returning "EnumName" rather than "caseLabel" for `String(describing:)`?

I need to get the string value of a non-String enum.

enum Numbers: UInt {
    case one = 1
    case two = 2
}

let one = String(describing: Numbers.one) // "one"
let two = String(describing: Numbers.two) // "two"

This seems to work fine and return the case name string for the given case.

But for a certain enum within Apple's frameworks, which is NOT visibly declared as @objc:

public enum FIMenuKind : UInt {
    case contextualMenuForItems
    case contextualMenuForContainer
    case contextualMenuForSidebar
    case toolbarItemMenu
}

it returns the enum name "FIMenuKind" instead:

import Cocoa
import FinderSync

let menu1 = String(describing: FIMenuKind.contextualMenuForItems)     // "FIMenuKind"
let menu2 = String(describing: FIMenuKind.contextualMenuForContainer) // "FIMenuKind"
let menu3 = String(describing: FIMenuKind.contextualMenuForSidebar)   // "FIMenuKind"
let menu4 = String(describing: FIMenuKind.toolbarItemMenu)            // "FIMenuKind"

Is this a bug in the private implementation of this particular enum?

Is there some other way to get the case name?

I assume this is an objc enum which does not store enum case names at runtime.

1 Like

Yep. ObjC enums don't have runtime metadata to print as their source-level names, so unfortunately, you'd have to extend them to be CustomStringConvertible yourself in order to print them.

2 Likes

I added the public enum declaration to the question.

Neither the enum nor anything in the FinderSync file have objc declared.

Is it possible that's declared privately?

The generated Swift interface for Objective-C types doesn't include the @objc modifier. The FIMenuKind type is nevertheless defined in Objective-C, in FinderSync.h in the FinderSync framework.

2 Likes

I encountered a similar issue with a refined C enum

__attribute__((swift_name("Enum")))
typedef enum __attribute__((enum_extensibility(closed))) {
    EnumCaseA __attribute__((swift_name("a"))),
    EnumCaseB __attribute__((swift_name("b"))),
} ModuleEnum;

Bit unfortunate that these lack case metadata and it has to be supplied in a Swift implementation, since enums of this kind otherwise import very nicely into Swift.