Have you ever wanted to share code between apps? I have and honestly, code reuse with Xcode (in particular between apps) is not as straightforward as you might imagine. You do have some options which I’ll talk about here and once you get something set up this problem will be solved easily.
The reason I started looking into this was because I wanted to release several variations of my app (or rather my app’s database engine). Previously, I have done this by simply copying the core libraries as needed. Essentially, each app of mine would have it’s own Xcode project and point (or have copies) of the code files I needed.
This solution is unsatisfying as hell and it became enough of a chore in terms of app maintenance that I ended up pulling many of my apps from the store in 2011.
So, last month I started to investigate some options that would help with code reuse among apps. But first, let’s backup and talk about code reuse and why most developers strive to reuse code.
Let’s Talk About Code Reuse
Coders will often be tasked with solving the same or similar problems when making software. Since most people don’t want to code or copy the same thing over and over again we try to come up with ways of organizing code so that we can avoid repetition. Instead of writing a few lines of code we will encapsulate that same code in a function that we can reuse over and over again. Write once and use forever.
Not only does this help us keep our code smaller we can avoid mistakes in the future because we will build on a collection of code we already know works. When bugs are fixed, they are fixed for anything that uses that code. Instead of correcting an algorithm in 100 places, we correct it once.
In an Objective-C program like an iOS app, you may see code reuse implemented with functions, classes that support sub-classing and delegation, categories and blocks. Most developers are comfortable with this practice at the app level.
Tasting Notes and the system behind the app already followed patterns that enabled code reuse since I’m a stickler for object oriented patterns. However, a problem emerged when I wanted to expand the reach of the Tasting Notes database engine.
The Code Reuse Problem Across Apps
Here’s what I wanted to do:
I wanted a entire suite of applications that used the Tasting Notes database engine.
The database engine is about 40% of the Tasting Notes code. Some of the apps in the suite could also reuse the user interface elements on the Storyboards, while others like the Mac version would also use the model classes. Many apps on the app store are a part of a suite like this and I’m sure they reuse the code that they can.
I was very surprised that setting up my app suite didn’t go as smoothly as I thought. What started as a day or two project ended up turning into a multiple weeks project where I tested my options with Xcode. Here are the solutions I tried.
Static Library with Xcode Workspaces
Surely this was the way to go right? My plan was to remove the database engine (and model classes) from Tasting Notes and turned this into a static library. The same would go for the standard user interface components. I would have started out with three separate Xcode projects that I could keep organized with one Xcode workspace.
This works in principle, but the reality of managing the three projects even at this level was a pain. The UI part would need to reference the model part which in turn was referenced by the app. Each one had it’s own frameworks to link. Odd linking errors would show up. This solution was it’s own kind of mess, however with the simplest situation it did work more or less.
Problems really started to happen when I attempted to add a Mac Cocoa app to the workspace. Obviously, I couldn’t reuse the iOS user interface. But it turns out that even the database engine couldn’t be added to my Mac app without a lot of very confusing configuration changes to the static library. This was the point where I gave up to look for better solutions.
BOTTOM LINE While the most obvious solution, the static libraries added too much work to the process to make it worthwhile to use.
Pointing to Code with Workspaces
The next thing I tried still involved using Xcode workspaces (I really thought that this was the way to go). What I did was create a group independent of any Xcode project in the workspace that held the shared code. This was once step up from what I did before.
This didn’t really help much either. First of – the way I set up the group folders meant that there was no Git support which I need. Of course, I could have added this myself but I wasn’t sure if I could actually integrate with Xcode in this way. Things were already starting to get to complicated.
Also, this solution didn’t help me as much as I wanted with or without Git. Each project needed to add each code file and there is almost a hundred of them. I also had to link to the other frameworks needed by my shared model classes. Linking to other frameworks isn’t a big deal when its the built in stuff, but including the Google, Dropbox and other third-party frameworks I use because a chore with this approach.
BOTTOM LINE This approach didn’t help at all and actually made some things a bit more difficult.
This is something I really didn’t know you could do. Or rather, I knew about multiple targets but was so entrenched in how I used to set up projects that I never really considered what the purpose or implications of multiple targets were. [Read more…]