Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift to Objective-C header does not contain Swift classes

I'm attempting to use Swift classes in my Objective-C code, however my Swift classes don't seem to appear in the generated header. As a result, my build fails with "Use of undeclared identifier 'HelloWorld'".

I used the templates to create a project called TestApp.

I have the following Build Settings in my target:

  • Product Name : TestApp
  • Product Module Name : TestAppModule
  • Defines Module : Yes

Apple's documentation says to use #import <TestApp/TestAppModule-Swift.h> but this doesn't work.

Instead, I'm using #import "TestAppModule-Swift.h" in my ".m" file. It seems to find this.

I'm able to navigate to it, and it looks like this...

// Generated by Swift version 1.0 (swift-600.0.34.4.5)

#if defined(__has_include) && __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#endif

...etc...

but no classes defined in there.

I have a Swift file in the project that looks like this...

class HelloWorld {    
    func hello() {
        println("hello world")
    }
}

Why isn't this working using the standard header file location #import <TestApp/TestAppModule-Swift.h>?

How can I get my swift classes in that header file, so I won't get the "undeclared identifier" error?

like image 788
TJez Avatar asked Jun 06 '14 16:06

TJez


People also ask

Can we use Swift class in Objective-C?

You can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header file. This file is an Objective-C header that declares the Swift interfaces in your target, and you can think of it as an umbrella header for your Swift code.

Can Objective-C class inherit from Swift class?

Unfortunately, it's not possible to subclass a Swift class in Objective-C. Straight from the docs: You cannot subclass a Swift class in Objective-C.


2 Answers

Here's how I have gotten it to work. You can see a more large-scale answer here.

Change this:

class HelloWorld {    
    func hello() {
        println("hello world")
    }
}

To:

@objc class HelloWorld { 

    class func newInstance() -> HelloWorld {
        return HelloWorld()
    }

    func hello() {
        println("hello world")
    }
}

Then, In your ObjC file:

#import "TestApp-Swift.h"

And call like this:

HelloWorld * helloWorld = [HelloWorld newInstance];
[helloWorld hello];
like image 60
Logan Avatar answered Oct 08 '22 11:10

Logan


tl;dr Ensure you have a bridging header if you're doing any cross-calling between Objective-C and Swift.

I had the exact same problem: I could see the -Swift.h file in DerivedData but it made no mention of my Swift classes. I was importing the header file correctly, the Defines Module setting was YES, and the Product Module Name was correct. I tried deleting and re-adding the Swift files, clean buiild, quitting XCode, etc, with no luck.

Then I realised I had no -Bridging-Header.h file in my project, presumably due to the way I'd cobbled it together from a previous project. Shouldn't be a problem because I was not (yet) calling Objective-C from Swift. But when I added a bridging header, and referred to its path in the build settings (Swift Compiler - Code Generation -> Objective-C Bridging Header), it magically fixed the problem - my -Swift.h file was suddenly full of SWIFT_CLASS() goodness!

So I'm guessing the bridging header is fundamental to the process, even if you're NOT using Objective-C from Swift.


UPDATE: I finally understand this. It is related to public/internal access modifiers. Not sure if I missed this originally or if it's an addition to the Apple docs, but it now clearly states:-

By default, the generated header contains interfaces for Swift declarations marked with the public modifier. It also contains those marked with the internal modifier if your app target has an Objective-C bridging header.

like image 35
Echelon Avatar answered Oct 08 '22 11:10

Echelon