Being an iOS developer, I spend most of my time writing Objective C code. It is fun and rewarding but often not enough to fulfil all of my product’s goals. One of the most important ones is portability. To create a successful mobile application these days we have to target at least two of the biggest platforms: Android and iOS. Does it mean that we have to implement the same functionality twice? Yes, to some extent. While we can’t avoid developing platform specific parts of our app (assuming that we want to develop in native code), we always have the option of extracting common business logic into a single C++ library that can be shared between the Android and iOS clients. Following this path can save us a lot of development effort and potentially increase the app’s performance by bypassing Objective C message sending infrastructure. In this post I will focus on how to build a simple C++ library and start using it within your Xcode project.
The code that we are going to use in this tutorial is a simple C++ implementation of a hash table. It consists of five files:
As I am not an expert C++ developer, the code is far from perfect and we are not going to discuss it in more detail. The code can be found on github.
Building with Xcode
Probably the easiest way to build our C++ code is to let Xcode take care of it. Let’s start by creating a new iOS project via File->New->Project. For the purpose of this tutorial I am going to choose the Empty Project template. Now it’s time to add our beautifully crafted C++ code to the project. Create a new group and drag all the files into it. It’s a good idea to keep the structure of the project on disk exactly the same as in the Xcode Navigator pane. The final result should look like this:
At this point we can already start using our C++ code! One important thing to note is that the extension of the files that include classes from the library will have to be changed to .mm. Let’s add some code into the app delegate class:
#import "hashtable.hpp" //... HashTable<int> hashtable = HashTable<int>(20); hashtable.putItem(20, std::string("A")); hashtable.putItem(21, std::string("B")); hashtable.putItem(22, std::string("C")); hashtable.putItem(23, std::string("D")); hashtable.putItem(24, std::string("E")); hashtable.printContents(); //...
Building and running the project will print the hash table’s contents to the console. Despite the fact that everything is working at the moment, we are not satisfied with the current solution. Our library files are mixed with the rest of the project and built as part of the same target, which is not ideal.
Creating a separate target
A better way to approach this would be to create a separate target which would include all of our library files and make the main target depend on it. Let’s give it a try. First, we have to select the project in the Navigator pane, and then click on the plus icon below the list of targets.
The template we want to select is C/C++ Library. In the next step we’re asked to give it a name and select the library’s type. In our case it should be static. We are going to use the new target to build our C++ code as a static library which will be linked with the binary produced by the main application target. Make sure that the Supported platforms value in the target’s build settings is set to iOS. Otherwise you are gonna get a linker error. Now it’s time to add some files to the newly created target. To do this, open the Utilities pane and make sure that target membership for the files hashtable.cpp and hashfunction.cpp is set to the static library target created in the previous step.
Since we are going to use the library in the code belonging to the main target, we have to make sure that the library’s target is built before building the iOS application itself. To do this we have to open the Build Phases menu for the main target and add our library as a dependency.
The final step is to tell Xcode to link our main application with the C++ library we created. This can also be done from the Build Phases pane of the main target. Just click on the plus under Link Binary With Libraries and select the appropriate item.
And voila, our application should be building and linking correctly. But wait a second, our library files are still mixed with the rest of the application, aren’t they? This is what we are going to fix now.
Probably the best approach to solving the problem we are dealing with is creating a separate project for the C++ library which is going to create a static library, and then nesting that project within other projects that will make use of the library.
This way we can have a clean separation between projects and we don’t have to worry about making sure that our client code is using the latest version of the library. A fresh version is built every time we build our main target.
Creating nested projects is very simple. First, we need to create a separate project for our C++ library and use the C/C++ Library template. After all the implementation files have been added, we need to find the project file and drag it into the tree structure of the client project. Next, we have to copy the steps from the previous section for making the main target dependent on the library’s target and linking with the library’s binary. To avoid linking errors, we need to add a new path to the main target’s Header Search Paths build setting. The path should point to the location where header files like hashtable.hpp are located.
The last change is modifying the application delegate file to include the line
Even though developing applications in both objective C and C++ may seem like a challenging task, it is definitely worth it. It can shorten your time to market and make maintaining your applications much easier, as you only have one codebase to take care of. With so many great resources on C++ available on-line, there is no excuse not to try!
As this is my first post on this blog, I would welcome any comments on what you like and what you dislike about the structure/style of my writing or the subjects being discussed. Thanks!