Why Does an @Objc Enum Have a Different Description Than a Pure Swift Enum

Why can I not print an enum's case name in Swift 3?

Because the enum is declared as @objc. In Legend.swift:

@objc(ChartLegendHorizontalAlignment)
public enum HorizontalAlignment: Int
{
case left
case center
case right
}

Try it yourself, add @objc in front of your Foo enum and you will see that Foo is printed. While I'm not exactly sure why this happens, it's likely it's due to the way @objc changes an enum's debug description, since Objective-C enums are just a series of Integers without any metadata attached. An @objc enum prints its type, while a Swift enum prints its case.

Related discussion: Why does an @objc enum have a different debug description than a pure Swift enum?

How to pass swift enum with @objc tag

Swift enums are very different from Obj-C (or C) enums and they can't be passed directly to Obj-C.

As a workaround, you can declare your method with an Int parameter.

func newsCellDidSelectButton(cell: NewsCell, actionType: Int)

and pass it as NewsCellActionType.Vote.toRaw(). You won't be able to access the enum names from Obj-C though and it makes the code much more difficult.

A better solution might be to implement the enum in Obj-C (for example, in your briding header) because then it will be automatically accessible in Swift and it will be possible to pass it as a parameter.

EDIT

It is not required to add @objc simply to use it for an Obj-C class. If your code is pure Swift, you can use enums without problems, see the following example as a proof:

enum NewsCellActionType : Int {
case Vote = 0
case Comments
case Time
}

protocol NewsCellDelegate {
func newsCellDidSelectButton(cell: UITableViewCell?, actionType: NewsCellActionType )
}

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, NewsCellDelegate {

var window: UIWindow?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)

self.window!.backgroundColor = UIColor.whiteColor()
self.window!.makeKeyAndVisible()

test()

return true;
}

func newsCellDidSelectButton(cell: UITableViewCell?, actionType: NewsCellActionType) {
println(actionType.toRaw());
}

func test() {
self.newsCellDidSelectButton(nil, actionType: NewsCellActionType.Vote)
}
}

How to reference Swift enum in Objective-C Header

What you want to do is called forward declaration. To forward declare an enum you can do:

enum name;

But since the compiler won't know the size of the enum, you will only be able to use it as a pointer in your header file.
Even doing this might prove problematic if you use compiler flags like -pedantic.

So in short, there is no good way to do this. Your best bet is not to, and access the enum from your implementation (.m) file instead.

In your implementation file, #import your swift bridging header file, and, without knowing more details about your problem, you could add private properties that use your enum like this:

@interface MyObjCClassDefinedInTheHFile()
@property (nonatomic, assign) SomeSwiftEnum type;
@end

Hope this helps.

Enums Interoperability between Objective-C and Swift

Swift 2: In Swift 2 you can now expose enums to Objective-C. Make the enum non-generic, inherit from a simple numeric type (like Int), and don't use associated values. Then it will show up in Objective-C with the name of the enum pre-pended to the cases so it looks like an Objective-C enum.

edit: To be sure it shows up, annotate it with @objc. If there are any issues preventing it from bridging automatically you'll get a compiler error.

Swift 1.x:
The answer is you can't, at least not currently. If you want to interoperate with enums you need to declare them in Objective-C.

As Nate says, use NS_ENUM and Swift will pull the definition in as an enum and strip off the prefixes from the values.

Why does declaring a combination of bit fields inside an enum produce a different result than declaring it outside of the enum?

You're not distinguishing between enum values and variables, but these are very different.


Enum abuse

As an aside, I think you're abusing the purpose of an enum by trying to sneak some extra metadata about these enumvalues (i.e. whether they are optional or not) into the composed Optional field.

I suspect the best solution for you is to move away from using the enum entirely, since enum values shouldn't have more metada surrounding them.

I have still answered the question as my suspicion of enum abuse is solely based on a name and my interpretation of its meaning to you. It's up to you to decide whether you're trying to sneak some metadata in the enum or whether I misunderstood your intention.


Enum values

[Flags]
enum Subjects
{
Art = 0b_0000_0001,
Agriculture = 0b_0000_0010,
Optional = Art | Agriculture,
}

When you include the composed value in the enum, you define it as a valid enum value. You are literally telling the compiler that Subjects.Optional is a valid (and thus meaningful) value of the enum, implying that this can and should be used.

That leads the compiler to use the Subjects.Optional value (and its string representation, i.e. "Optional") because you told the compiler that it's meaningful to you.

Variables

[Flags]
enum Subjects
{
Art = 0b_0000_0001,
Agriculture = 0b_0000_0010
}

var optional = Subjects.Art | Subjects.Agriculture;

It's important to realize there that optional is a variable and not an enum value. There are only two enum values here, Art and Agriculture.

In this case, you did not define Optional to be an enum value, and therefore the compiler cannot use or refer to an enum value that doesn't exist.

Therefore, it falls back on figuring out which combination of enum values would result in the (combined) optional value, and it realizes that by combining Subject.Art and Subject.Agriculture, you get the value described by optional, which is why it returns a comma-separated string Art, Agriculture.


If you want to get the comma-separated string while also retaining the composed values in the enum itself, you're going to have to generate the comma-separated string yourself. For example:

public string AsCommaSeparatedString(Subjects myEnum)
{
var possibleSubjects = new List<Subjects>() { Subjects.Art, Subjects.Agriculture };

var subjects = possibleSubjects.Where(possibleSubject => myEnum.HasFlag(possibleSubject));

return String.Join(",", names);
}

You'll have to list all the enums values which you want to include (so others like Optional will be ignored), but that's unavoidable when you specifically want to exclude some values (like Optional) from being mentioned.

Multiple protocol conformace in enum doesn't work

Changing the enum Definition from enum Theme: Int, CaseIterable, CustomStringConvertible { to enum Theme:ThemeProvider { does not make Theme automatically have a T, which is required by ThemeProvider.

And if you add typealias T = Theme then the Theme enum does still not have Int, CaseIterable, CustomStringConvertible, cause typealias T = Theme does not make any type(Theme here) conform any protocol.

That's why enum Theme: Int, CaseIterable, CustomStringConvertible, ThemeProvider { typealias T = Theme ... is required to make Theme conform to ThemeProvider.

What you probably want is enum Theme: Int, ThemeProvider { where ThemeProvider is public protocol ThemeProvider: RawRepresentable, CaseIterable, CustomStringConvertible {}.

More can't be said without any example.



Related Topics



Leave a reply



Submit