Introduction
Xcode Version: 4.3.3 (build 4E3002)
Durning this article I will be focusing on a few of our own developments and what we have learnt over the past few years. There are many articles on different aspects of application development so I wanted to try and give you a high level picture of all the pieces and how they fit together. I shall be covering version control, static libraries, unit testing, Xcode workspaces and documentation. If you think I've missed anything or you have any thoughts, please comment.
So, let me start by giving you a little background on my open source project, TBXML. During the development of Sir Lamoraks Quest, we decided to use XML as the storage format for all map data as it's easy to parse and is the output generated by the Tiled map editor. However, we soon ran into a problem. XML parsing on iOS was just too slow. It could take anything up to 40 seconds to load one of our map files. Once we had identified NSXMLParser as the culprit, I set to work on a new lightweight XML parser, focused solely on performance… TBXML was born.
TBXML is a fairly simple program, consisting of just a few source files. It's very fast and has a really simple API, an important consideration as this parser was to be used in Mike's game, and talked about in his forthcoming game programming book.
I setup a website to host the TBXML project and put together a little documentation and a sample project to get people going. I stuffed the latest TBXML source files into a zip file, uploaded it to the site and wrote down a list of recent changes. Every time I wanted to update the project, I zipped up some more files, altered a few web pages and shipped it off to the server.
3 Years on and TBXML is being used in numerous projects for a whole variety of tasks. We're using TBXML in practically all our projects and there's even projects on GitHub built on top of TBXML. But TBXML itself is still not version controlled!
I'm now in a situation where I have numerous projects, each with its own unique copy of TBXML. I also have several copies of TBXML floating around that implemented various features that have never been put live. It's hard to update, distribute, document and fix bugs in TBXML.
So I've decided to take a step back (just a couple of inches), to look at how I organize my projects. Project organization and workflow have a big impact on your ability to deliver a polished product. During development you'll add and delete code, import a couple of libraries, duplicate code from another project, refactor most of it and compile it countless times until you end up with something almost completely different from your spec ;)
So I set out a few targets that would kill off my beloved bad habits and force me to do things the right way.
Targets
- All source code should be version controlled
- Any common code should be separated out to a shared library
- It should be trivial to compile a shared library for multiple platforms and different build modes (debug/release)
- It should be easy to add a library to an existing project and keep it updated
- Open source projects should be easily shared with the community and painlessly updated
- Documentation should be automatically generated from the source code
- Library code should be thoroughly tested before being released
After vast amounts of research, I found that with just a few different existing and readily available technologies, I could achieve all my targets.
Technologies
- Xcode workspaces, static libraries and unit tests
- Git version control system with GitHub.com for hosted git repositories
- Apple Doc project for auto building documentation
Static library or framework?
What are they?
Static libraries and frameworks allow you to share duplicate blocks of code between multiple projects easily, meaning you could update your common code once and have all projects benefit. Plus your code library can be fully version controlled, have its own set of unit tests to ensure integrity & be distributed to other developers. You would also create a static library or framework if you wanted to sell your code to a 3rd party but wanted to keep the source code private.
What is a Framework?
Typically, a framework is a common library of code that your application can dynamically open at runtime. The advantage of a framework is that is contains everything the library needs in a single archive. This could be compiled code, header files, or other resources like images or nibs. Unfortunately Apple does not allow dynamic frameworks on iOS devices. I'm guessing this is to stop Joe Public from downloading potentially malicious code to their devices.
What is a static library?
A static library is a bunch of source files, compiled and crammed into a single binary file with the .a file extension. When you build an application that uses a static library, the linker will scan the library for unknown classes or methods and merges them into your executable. The resulting executable file is a combination of compiled application code along with any required code from static libraries.
Can't I use a static framework?
When Apple decided not to support dynamic libraries on the iOS platform, they removed the redundant 'iOS Framework' template from Xcode. It used to be possible to tweak this framework template to support static libraries instead of dynamic ones. These static frameworks were perfectly valid on the app store because ultimately, they were just static libraries wrapped up in a nice directory structure. There's been quite a lot of work put into a project that aims to bring back the static framework. I've not tried this myself but it does look promisingÂ
https://github.com/kstenerud/iOS-Universal-Framework. You could also try following through this list of instructionsÂ
http://simplyitinc.blogspot.com/2011/04/creating-static-framework-in-xcode-4.htmlVerdict
I've decided to stick with static libraries for my own projects as they are Apple's recommended method for distributing code and are therefore less likely to break in future versions of Xcode. I also believe that support for static libraries will grow in later versions of Xcode making them easier to use.
Workspaces
What are they?
To aid developers in the use of static libraries, Apple has included a new feature in Xcode called workspaces. Workspaces allow you to group a bunch of related projects together, and set dependences between them. So in my case, I have an application project that makes use of the TBXML static library. Both projects sit side by side within the workspace. Check out Apple's documentation on workspaces for more informationÂ
https://developer.apple.com/library/ios/#featuredarticles/XcodeConcepts/Concept-Workspace.htmlBenefits
- Refactoring - Refactoring operations act across all projects within a workspace, so you could refactor the API of a library and propagate the changes through all applications in one operation.
- Indexing - Indexing is performed across the entire workspace so features like code completion and jump to definition work seamlessly.
- Building - When you build your application, any associated libraries will also be built if necessary. When Xcode builds your library, it will do so for your current build configuration (Debug, Release) and link it to your app. This avoids having to pre-build your library for each configuration / deployment target.
Issues I encountered
I was stumped for quite some time on a very trivial task, adding a static library project to the workspace. I had begun experimenting with static libraries within workspaces and was familiar with dragging a project to the workspace. I would then be able to see the entire project and manipulate it. All of a sudden, dragging a static library into my workspace stopped working. Instead of seeing the familiar project layout, I saw just the project file listed in the workspace with no disclosure button. I eventually figured out that Xcode prevents you from viewing a project if it's open elsewhere. That includes being part of another workspace. Further more, Xcode won't allow you to compile a project unless it has exclusive access to all projects.
Verdict
Workspaces are a great addition to Xcode and I wanted to make full use of them. Most of my applications use the TBXML library and I quite regularly work on more than one application at a time. Especially If I need to dive into another application to fix a bug, then return to previous development. With Xcode's restriction of only opening a project once, my only option would be to have a separate copy of the TBXML static library in each project. But this goes against my target of not duplicating library code. This is where Git repositories come in, specifically submodules.
Git version control system & GitHub hosted repositories
What is version control
Version control is a system that maintains a history of changes to a bunch of files over time. This makes it ideal for software development where files change radically during the course of the project. There are many version control systems available, each with its own unique list of features. Git is one such version control system thats seen a lot of attraction since its introduction in 2005.
Why Git?
Git provides a next generation version control system. The reason Linus Torvalds developed it is because other version control systems like CVS and Subversion sucked! Subversion is still heavily used in the industry and fixed many of the issues with CVS. However, as time has passed and developers started working in a more distributed environment, Subversion began to struggle. Git was designed with a focus on performance and distributed development. One of its key features is the fact that it's server less. Every Git working directory is a full repository in its own right. You would then sync changes between them. Further readingÂ
http://en.wikipedia.org/wiki/Git_(software)Why use a version control system?
For quite a long time none of my code was version controlled. I had a development folder I'd stash all my projects in, zip it up every so often, burn it to an unmarked disk or whack it in a folder on a web server called "backup". I've since discovered the benefits of using a version controller, specifically a hosted version controller. The biggest surprise to me was that version controlling projects takes less time than trusty zip system! on GitHub.com It's a trivial task to setup a repository for a new project. Once in place you can hit the commit button every so often and be safe in the knowledge that everything is backed up, with a full version history. Add to this the ability to sync changes between multiple machines (say if you have a desktop and laptop), or sync the project to a friend. I remember I used to zip up a project, and send it to Mike over Skype. Each time I made a change I created another zip file of at least 20MB and sent it across. It's fiddly to do and takes ages to transfer. Now, I sync my changes and Mike pulls them. Within seconds he's running my latest code. Version control makes collaborative development possible, easily merging changes between you and your piers.
Other Git programs for OSX
In it's native form, git is a command executed from the command line, and as such can only be used in terminal. However, there are many OSX apps out there that slap a pretty GUI right on top of it. Below are a couple of common apps.
Integration with Xcode
Git has been fully integrated into Xcode since the introduction of version 4. Apple have put together some detailed documentation on how to use Git source control with Xcode. http://developer.apple.com/library/mac/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/085-Save_and_Revert_Changes_to_Projects/manage_project_changes.html#//apple_ref/doc/uid/TP40010215-CH7-SW12
Hosting your own private Git repositories
Git Submodules
After discussing the ins and outs of Git, I finally get to the really cool bit I want to talk about… submodules! Git submodules allow you to clone a remote git repository inside of another git repository. You would use this feature when your working on an application (like TBXML-Books) and need to include an external library (like TBXML). The external library could be maintained by another developer, or yourself if your sharing code between multiple projects. There is a great writeup hereÂ
http://book.git-scm.com/5_submodules.html on submodules. Every submodule you add to your git repository maintains its own identity and therefore have a complete revision history for the referenced external project.
Git submodules point to a specific commit on the external repository. The reasoning for this is that you can build your app against a known good version of the library and everyone checking out the project will also get the exact same version of the library, even if several commits have occurred in the meantime.
Pitfalls with submodules
It is possible to update the submodule and push the changes to the remote repository. When doing this, your submodule will acquire a new commit ID. When committing the parent project, git stores the submodule's URL and commit ID. If you accidentally commit your parent project first, anyone checking out the project will end up with an old version of the external project.
Unit tests
Why unit tests?
How many times have you written a bit of code and hacked in a quick test to your AppDelegate.m file? I've done this quite a bit to test code. It gives me a quick way of testing a class or method. Once I'm finished, I just blow away the code and continue working on my application.
Whats the problem?
I've just deleted a really useful piece of code that verifies my class is working as expected. So, several months later when I'm adding functionality to that class I find myself writing another bit of test code in the AppDelegate.m to test it again. What a waste of time!
Unit tests to the rescue!
Unit tests are quite simply little snippets of code that test a specific function of a class. The benefit here is you can build up a collection of these tests and have the compiler automatically run them on your project. If any tests hit a problem, the compiler reports it as an error. So, several months later I'm adding more functionality to a class. I tell Xcode to compile and test my app and Xcode tells me if any of my test code failed. I know instantly if I've messed up and introduced a bug into my previously stable bug free code.
There are a few more benefits to setting up unit tests other than catching your own mistakes. When Apple decides to release a new operating system, you can quickly test your libraries to see if any unexpected bugs have been introduced from parts of the system they've changed. Also, If you distribute your code to other developers and they find a problem, they could add a unit test to help communicate the problem and make sure it doesn't return in a future release.
Generating Documentation
Documenting your projects can really improve the usability of your code, especially as it grows with more functionality over time. This is not only important for public code libraries, but also your own private code. It's a great resource to refer to when you can't quite remember what a function does or the purpose of a class. It also helps you communicate your class design to other developers meaning they don't have to delve into the code to find out what it does.
During my research I found two good documentation generators
Finishing up
So we've come to the end of the article. I've tried to cover many topics and I'm sure there are many more and lots of alternative ways to do things, but hopefully it's given you an idea on my thoughts and project workflow. I hope that from this article you'll take away the knowledge that a little effort can have a huge impact on your project.