Chances are, during migration from Objective-C to Swift, you would be doing it gradually. Therefore, you’ll spend a lot of time with a mixed-language project of Objective-C and Swift interoperating. A lot of confusion happens during this period of time just because of not knowing what to do to expose code written in these two languages to each other.
Swift Bridging Header
This article is focused on exposing Swift to Objective-C files, which can easily be done by adding the following import to any .m file you’d like to access the Swift code from:
#import "Project_Name-Swift.h"
You can read more on these here.
Introducing Precompiled Headers
However, the previous approach is mundane and can increase build time dramatically for each new Swift file added no matter how modest it is. Thankfully, there’s a solution for this, precompiling bridging headers or PCH for short. Check out this article for more context on what a PCH is and the reason behind its origin.
How can I use PCH files?
- In Xcode, go to New file > iOS:Other > PCH file.
- Name it something like (Project-Name)-Prefix.pch.
- In Build Settings > Apple Clang - Language, set Precompile Prefix Header to Yes.
- In the Prefix Header field, add the path to the PCH file you just created $(PROJECT_DIR)/$(PROJECT_NAME)/(Project-Name)-Prefix.pch.
- In there, you will need to import the automatically generate Swift Bridging Header which will be named something like (Project_Name)-Swift.h.
Note: You can search for the Swift bridging header using the Open Quickly command (Cmd+Shift+O) but you need to make sure that you build your project successfully with the Swift files in it.
PCH File Example
Here is an example of a PCH file produced by Swiftify:
What about the .h files?
Now all your Swift classes should be accessible in your .m files, but what about the .h files? For that, you will need to use forward declarations. Assuming that you want to use a Swift class called MySwiftClass, the forward declaration would look like the following:
@class MySwiftClass;
This is to prevent Objective-C classes from inheriting from Swift classes.
Comments
6 comments
Have you ever run into an issue, where it works if you import the header individually into the .m files, but when you put it into the .pch file, it produces a "file not found" error?
Here is a thread about this issue that seems to not have a solution:
https://stackoverflow.com/questions/39471019/imported-xcode-generated-swift-header-not-found-in-pch-file
Hey Justin,
I. You should normally wrap the statement to import the Swift Bridging Header file under `#ifdef __OBJC__` ... `#endif`, exactly as suggested in this article.
II. In my experience, using a Swift Bridging Header is usually a "two-edged sword" case:
1) In order to have the Swift Bridging Header file generated, you need your project to compile successfully (and have at least one Objective-C and at least one Swift file);
2) Sometimes it's tricky to get the project compiled before the Swift Bridging Header file is generated.
For troubleshooting:
i. First, try to get to the point when you can build the project successfully.
ii. Find the Swift Bridging Header (`ProjectName-Swift.h`) under the DerivedData folder (go to Xcode -> Preferences -> Locations to navigate to this folder).
iii. Once the above works, try importing your Swift Bridging Header file from the PCH file.
Let me know how the above suggestions work for you!
Unfortunately, it still has "ProjectModuleName-swift file not found".
I guess I'll just keep importing it per file. I wonder why Apple made all this integration stuff so messy. I guess pure swift projects are the future haha.
I got you, Justin.
Indeed, that would be difficult to investigate without touching the project.
If you think that would help, you could strip down the project that demonstrates the issue and send it privately to alex(at)swiftify.com.
Otherwise, feel free to proceed with your approach.
I have added a sample project where Objective-C <-> Swift interoperability works both ways (using the .pch file) under
https://github.com/Swiftify-Corp/Swiftify/tree/master/BridgingHeader/TestObjc
Hope that will be helpful to understand how things should work, and compare to your project.
Hi, I have two questions 1. Can this approach apply to the framework? 2. The swift file imports the objective-c header file through the "-bridge-header.h" file, and the objective-c header file imports "projectName - swift.h" through the pch file, so there will be circular imports, so there should be problems ? Please help to answer
Please sign in to leave a comment.