Using C, C++ and Objective-C frameworks in Swift apps
I did a talk in try!Swift Tokyo this year about using C, C++ and Objective-C frameworks in Swift apps. The presentation was quite concise, so I decided to write down the content in details to provide more information.
The structure of this article will be divided into:
- Language connections among C, C++, Objective-C and Swift
- How to set up dependencies
- Why wrappers and how to write wrappers
Language connections among C, C++, Objective-C and Swift
C to Swift
C is 47 years old, and Swift is a new powerful open source language that has support for C. Even though it can not compile C code it has direct interoperability with C, so we can use compiled C code directly in Swift.
C++ to Swift
C++ and Swift can not talk directly and it needs some manual middle stage, for example C or Objective-C.
C++ is a superset of C and it provides the support of object oriented programming. Since Swift supports C one approach is to expose the C++ library with a C only API, and Swift apps can then use the library directly.
Objective-C++ can compile source files that contain a combination of C++ and Objective-C. The other approach is to include the C++ library in an Objective-C framework and expose that to Swift.
Objective-C to Swift
Swift is built to work with cocoa and a large body of existing Objective-C code so communication between Objective-C and Swift are very straight forward.
How to set up dependencies
To be able to use frameworks in a project we first need to set up dependencies. I will show them one by one.
C library to Swift app
A C library is often compiled as a static lib, the challenge here is that libraries do not contain interfaces. Swift doesn’t read header files automatically neither. So we have a problem here: C headers are not visible. The trick to solve this problem is to use module maps. For step to step guide on setting up a C library dependency in a Swift application please read my other medium article.
C++ library to Swift app
As I mentioned earlier Swift can not talk to C++ directly so let’s add some manual middle stage, for example create an Objective-C framework that includes the C++ library. Inside the Objective-C framework we need to wrap all C functionalities into Objective-C. To be able to compile both C and Objective-C in one file the trick is to use Objective-C++. We can do that by simply renaming the .m file to .mm. For detailed setups please take a look at this medium article.
Objective-C framework to Swift app
To be able to use Objective-C frameworks in swift applications the setup is really simple. We need to include the Objective-C framework or project into the swift application. If we are not using any dependency management tool, we can simply drag the Objective-C xcodeproj or framework into the swift project. Afterwards link the framework and import the Objective-C module, now we are done.
Why wrappers and How to write wrappers
We have successfully set up dependencies for C, C++ and Objective-C, does it mean that we can start to use them directly in our swift applications? Well both yes and no.
Objective C translates well to Swift so we don’t need to do much there. C++ on the other hand doesn’t translate at all as we saw earlier. In between we have C, that we can work with without additional code, but the interfaces generated on the Swift side is not always super developer friendly and sometimes requires a few lines that we don’t want to repeat a lot.
To make the interface Swift friendly and to abstract some underlying details away, that’s exactly what wrappers are for.
C is the oldest among these 4 languages. C manages memory manually, it also has pointers that Swift doesn’t have. To use C functionalities in Swift it sometimes requires us write a few lines that we don’t want to repeat a lot. Therefore it is worth it to write a clean and Swift friendly interfaces.
I have created a sample C framework and tries to map the problem and solution one by one. For details, please take a look at this github project.
If we are about to write an Objective-C wrapper for C++ library we need to understand how Objective-C and C++ talks to each other. For example how to convert C++ string to Objective-C NSString, how to instantiate a C++ class instance in Objective-C. For more details on how these problems are solved please check this github project.
As Swift is built to support a large amount of existing Objective-C code there’s no particular need to create a wrapper for it. If we are dealing with really old Objective-C frameworks we might want to use NS_SWIFT_NAME to convert some class and functions names to be more swift like.
What do you think? If you have questions, suggestions or want to discuss more with me, reach out to me on Twitter @humlelu.
Thanks for reading! 🌸