3

I have a method that uses a forward declaration of a Swift enum. Whenever I do this my method isn't visible in other Swift classes. Yet if I do a forward declaration for a class it is visible in Swift. Why is it not visible for an enum and how can I get around this?

// Objective-C Header file 

@class ViewController;
typedef NS_ENUM(NSInteger, MyEnumType);

@interface ObjcViewController : UIViewController
- (void)doThis: (enum MyEnumType)type;
- (void)grabTheClass: (ViewController *)mySwiftClass;
- (void)doSomethingElse;
@end


//Swift File 

@objc enum MyEnumType: Int {
    case one = 1
    case two = 2
}

@objc class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let controller = ObjcViewController()
        controller.doSomethingElse()
        controller.grabTheClass(self)
        controller.doThis(EnumType) //ERROR: This will not compile
    }
}



code here

2
  • 6
    Post code as text and not as images Commented Mar 22, 2021 at 16:16
  • Use NSEnum to define a type. Nothing else. Don’t use “enum”. Commented Mar 22, 2021 at 19:46

2 Answers 2

2

The forward declaration of the enum creates an incomplete type. And an incomplete type has very little usefulness. You can form a pointer to it, or you can call a function with a pointer to it, but that's it.

Unless you complete the enum declaration with the concrete definition, you won't be able to properly consume it, neither in Objective-C, nor Swift.

And this is why the Swift code can't see the method, because at the time the Swift compiler processes the bridging header (and this happens before any Swift code is processed), the enum is not yet materialised, thus is excluded from the bridged interface due to being an incomplete type.

If you add a method that takes a pointer to the enum:

- (void)doThisWithPointer:(enum MyEnumType *)type;

then the method will be accessible from Swift, though it will be imported as

func doThis(withPointer type: OpaquePointer)

which doesn't make it much more helpful either.

But if forward declarations are incomplete types, why does the @class works? Its because in Objective-C objects are passed as pointers, and pointers to incomplete types are usable at call sites (as we just saw). Thus, the method is available to Swift.

More, the @class statement is part of the Objective-C additions to the C language, which means the compiler can give them special treatment, like importing the method with the expected signature, instead of the OpaquePointer one. This thanks to the dynamic nature of the OOP additions over the C language.

Sign up to request clarification or add additional context in comments.

Comments

0

It looks like doThis is a function, but you are missing the parentheses in the call. The line controller.doThis should instead read controller.doThis()

See if that helps.

Somebody else claimed in another post that the Swift enum needed to be declared as public in order to be visible in Objective-C. I haven't verified that however.

Edit:

Okay, after some experimentation and googling, I think you have to declare your enum in Objective-C using the NSEnum macro, and that makes it available in both languages.

I don't think Objective-C can "see" Swift Enums when they're defined in Swift.

4 Comments

I fixed the example code. The code when fully written out will not compile, so it's not just an Xcode suggestion issue. I just tried the public keyword. That unfortunately doesn't work either.
In your new code, you are trying to invoke doThis() on a function that takes a named parameter of type MyEnumType. What you are passing in is the TYPE, not an instance of that type. Your call should read doThis(.one) (You should pass in a value of type MyEnumType, not the type.)
Yeah same thing. It will say the class has no member doThis(MyEnumType.one)
I confess, I avoid Swift/Objective-C hybrid apps nowadays. I think Gnasher may be right that you have to declare your Swift Enum as an NSEnum type in order for it to work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.