Consuming a C++ Library from Swift

Learning Swift

This year, I had the opportunity to learn Swift for a project. At the outset, I have to admit that I’m a novice at Objective-C and the language never “clicked” for me, so jumping into Mac-style development was quite a challenge! Additionally, the very first project I was thrown into contained bits in Swift, Objective-C, and C — with an enormous amount of communication between Swift and C. Surprisingly, this mostly wasn’t too bad; the worst I would face was a bit of weird casting between Swift-friendly and C-friendly raw data types. Swift itself was much, much quicker to come to terms with than Objective-C had ever proven to be.

“Great,” I thought! “I’ll use Swift for the iOS version of my long-languishing fitness app!” You see, once upon a time, I had this concept for an app. The cool unique feature is an AI library, and of course, I hope to someday convince a colleague to port the UI to Android. Meanwhile, I can write it natively for iOS, and just share my C++ cross-platform AI code, right? I leapt into my backlog, pulled out my old C++ AI engine, and started trying to connect it to Swift.

And was met with a barrage of compiler errors.

A weekend of digging helped me find the roots of all of my issues, but my Google-fu led to surprisingly weak results. Unfortunately, it seems that C++ coding is considered the domain of Pretty Skilled Developers, and the explanations that PSDs give to each other are terse, technical, and really hard for Objective-C newbies like myself to follow.

About This Tutorial

This tutorial will demonstrate how to consume a C++ library from a Swift application. In order to do this, you will:

  • Begin with a C++ library — this tutorial will use a simple example clas.
  • Add a Bridging Header to your Swift project
  • Build an Objective-C++ interface class
  • Call the Objective-C++ class from Swift

A ZIP file containing a working version of this tutorial can be downloaded by clicking here (and this link will be included again at the end of this article).

For a sample case, we will consume an intentionally trivial class containing basic information about a rectangular banner — location, size, and text contents. While this class itself may not be particularly useful, the concepts are generalizable to most other libraries.

The Library

The C++ library to be used contains a simple class that implements a stateful rectangular banner.

Building a Bridge

There are two components to bridging between the world of C++ and Swift: the Bridging Header, and the Bridging Interface Class. The Bridging Header will make code visible to Swift, while the Bridging Interface will wrap up all of that C++ so that the compiler doesn’t have to see it. The tricky part that I had to puzzle out was that the Bridging Header will always compile as Objective-C, not as Objective-C++. What does this imply for you? It means that the Bridging Header cannot include any C++ headers. However, it CAN include header files that expose the implementation of Objective-C++ classes — IF the implementation can be defined without C++! If this doesn’t make sense yet, it will by the end of this tutorial. The Bridging Interface, therefore, has to be written in Objective-C++.

The spectrum between Swift and C++

The spectrum between Swift and C++

  • Swift will contain the bulk of your UI and application logic. The bulk of your codebase will likely be here.
  • The Bridging Header allows C-style code to be visible to Swift.
  • A Bridging Interface Class is a thin wrapper that keeps C++ on the other side of the Wall Of Headers. This is also a convenient place to map between your Swift-friendly datatypes and raw, low-level C/C++ datatypes.
  • Your original libraries in C++ should remain unchanged in this process.

Once you add your first “mixed” source file (either by adding C/C++ to a Swift project, or Swift to a C/C++ project), you will be prompted by XCode to automatically add a Bridging Header. This is the easiest way to add this file, so I recommend clicking Create Bridging Header here. However, if you miss it this time, you can still add one manually.

Bridging Header Prompt

Bridging Header Prompt

Now that you’ve introduced C++ files and set up your Bridging Header, you should add an Objective-C++ class to your file. After assimilating the class methods available, it was fairly clear to me that my main interface needs would be to get/set the rectangle through a CGRect object, and to interact with the banner text via an NSString.

The key trick in this segment is using a void* property to “hide” the C++ class that will ultimately result from the Objective-C compiler. Since this header file is not allowed to include C++, it can’t be aware of my C++ class; it will find all sorts of keywords it doesn’t understand like “namespace” and “class,” after all! However, it IS going to need somewhere to hold its state in memory, so a void* property is declared and will be cast back and forth later. Ideally, I would extend this with some macros to make it prettier for consumers, but for the purposes of this exercise, it’s being left in its simple native data type.

At last, we can implement the interface. First, we will override init and dealloc so that we can instantiate our C++ object and store it in our void* property (and delete it when we are finished as well).

Once we have instantiation handled, we can implement methods to intelligently translate our data back and forth between our application and our stateful class instance. These implementations have a pretty significant amount of inefficiency, as they are intended to be simple to read instead of highly efficient.

Crossing the Bridge

With our Bridging Interface in place, we can construct an application that uses our library. In this case, I built a simple UI to use the RectData instance to control the contents of a single UILabel on an iPhone. Much like the Bridging Interface class design, the application implementation here is intended to be simple to read and understand, but is not a very efficient code design.

Finally, we have an interface that allows control of the UILabel based on the current RectData values; to demonstrate this, the sample application polls the RectData on a timer and updates the UI display. The rectangle can be moved and resized, and its contents changed.

Swift-C++ tutorial screenshot

I may have gotten a little carried away, covering my UI with the test rectangle…

Conclusion

Using Objective-C++ classes as an intermediary bridging wrapper allows Swift applications to use existing C++ libraries, enabling access to many cross-platform tools. By using void pointers to hold references to C++ class instances, the compiler wall between Objective-C on the Swift side and Objective-C++ on the wrapper side can be maintained.

I hope this tutorial saves someone else from at least some of the pain I had to go through in figuring out some of the details involved in this process… Happy coding!

Download a ZIP file containing a working version of this tutorial for XCode 7.2 by clicking here.

Tags: , , , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *