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
Swift Difference Between Final Var and Non-Final Var | Final Let and Non-Final Let
Is There Any Way of Locking an Object in Swift Like in C#
Swift Error: Missing Argument Label 'Name:' in Call
Result Values in '? :' Expression Have Mismatching Types 'Some View' and '...'
Uitesting Xcode 7: How to Tell If Xcuielement Is Visible
How to Block Users on Firebase in a Social Media App? for iOS
How to Use Dispatch Groups to Wait to Call Multiple Functions That Depend on Different Data
Reading an Inputstream into a Data Object
Uitableview - Multiple Selection and Single Selection
Swift: How to Change a Property's Value Without Calling Its Didset Function
How to Make Rounded Corner Progress Bar in Swift
Calculate Area of Mkpolygon in an Mkmapview
Translucent Status Bar with No Navigation Bar
Get Index in Foreach in Swiftui
Swift Package Manager - Type 'Bundle' Has No Member "Module" Error