Reputation: 2029
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:
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?
Upvotes: 20
Views: 14658
Reputation: 257
Maybe you defined a Swift class with the same name as an existing Objective-C class which wouldn't be unusual if you want to refactor your Objective-C code to Swift.
As long as you have a class defined simultaneously in Swift and Objective-C the compiler quietly stops updating the bridging header altogether ("ProductModuleName-Swift.h"
) - which also affects subseqeuent changes in other bridged Swift files.
For general reference how to import Swift into Objective-C see: Importing Swift into Objective-C | Apple Developer Documentation
Upvotes: 0
Reputation: 885
In my case, by following Apple guidelines, it did not work until I ran the project. The xcode editor kept flagging the unknown swift class, until i clicked "run". The build succeeded, and the swift method worked.
Upvotes: 1
Reputation: 41
In my case the class was not being compiled, because I first added it to my test target only... After adding it to my main target (Build Phases -> Compile Sources), it was actual compiled and added to the header file.
So much for TDD ;-)
Upvotes: 0
Reputation: 7922
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.
Upvotes: 21
Reputation: 1076
A more convenient way would be to inherit from NSObject. Like so:
class HelloWorld: NSObject {
func hello() {
println("hello world")
}
}
Upvotes: 3
Reputation: 53112
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];
Upvotes: 22
Reputation: 49395
It is proper to use #import "TestAppModule-Swift.h"
in your .m files. If you need to reference a class in a .h, use the @class
forward declaration.
Further, if you want to use a Swift class from Objective-C, the Swift class must be marked with the @objc
attribute. Xcode will only include classes with that attributed in the generated header. See also this documentation.
Upvotes: 12