
One challenge we faced while developing iOS apps was to optimize using of third party components and even those developed internally. Although it might look an easy task, it can become a nightmare if not well organized.
In this post we describe our experience, the pros and cons of each distribution type and also how we are dealing with this now.
The main reason of components usage is code reusing, resulting in a much faster project development. Our bigger concern here is related to version control, avoiding changes on the components source code inside each project, solve library interdependence and also easying the process of adding a new component to a project.
In general, iOS libraries can be distributed as source code, static library or static framework. In this article, we will describe each of these aproachs.
Source code
You just have to add the source code files to your project and build them as if they were part of the main project.
Pros
- - easy to use;
- - easy to create;
- - easy to debug.
Cons
- - hard to manage version-control;
- - separation between project and components;
- - component modification inside projects;
- - library interdependence is user responsible.
Although it is easy to use components this way, it is not easy to control which version is being used. Moreover, all the source code is added to the project promoting the user as responsible for “external” code organization.
Another problem of this kind of distribution is dealing with source code changes by users. If this happens and nobody identifies, the use of this component is compromised.
Static Library
These libraries are already compiled before distribution. It has a library (.a file), headers (.h files) and sometimes resources.
As it is compiled, its distribution does not allow the user access to the source code. Also, there is no need to be compiled within to the main project, resulting in a much faster compilation time.
Pros
- - easy to use;
- - separation between project and components.
Cons
- - Categories bug;
- - needs project configuration changes;
- - library interdependence is user responsible;
- - creation of the distribution package;
- - debugging difficulty.
When a Static Library uses Categories we need to add the argument -ObjC on the “Other Linker Flags” project configuration (more information here) so that it is loaded by the Linker. However there is a known Linker bug in iOS and 64-bit apps that prevents -ObjC from loading files with only Categories and no classes. There is a workaround that consists to use the flag -all_load together with -ObjC, so that the Linker loads all files.
The Static Library dependencies must be added by the user or included in the Static Library itself, but the last option is not a good option, once it becomes limited to the version specified by the dependence and, also, we can have problems with duplicated symbols (due to -ObjC and -all_load flags used together).
After creating a component, we must create a package with the library (.a file), all the public headers and the resources for each different version.
Static Framework
Unfortunately Cocoa Touch does not allow us to create Dynamic Frameworks. Only Apple can create them, such as UIKit and Foundation. However, we can create Static Frameworks, which are nothing else than Static Libraries with a directory structure that has headers and resources.
There is no templates to create iOS Static Frameworks natively available on XCode, but there is a project on github with scripts to enable this option.
Pros
- - easy to use;
- - separation between project and components;
- - creation of the distribution package.
Cons
- - Categories bug;
- - needs project configuration changes;
- - library interdependence is user responsible;
- - hard to debugging;
- - needs to add XCode templates.
This alternative has the same advantage and problems of Static Library, but makes the component distribution easier, once the Static Framework template creates the directory structure with project headers and resources.
Among these alternatives we have not find one that easily solved the interdependence question between libraries and that was kind a “plug-and-play” to users, until we find out CocoaPods.
CocoaPods
CocoaPods is a libraries dependency manager open-source project for Objective-C, similar to what RubyGems is to Ruby. Its goal is to make the process of adding a dependency to a project easier and also create a centralized ecosystem of libraries available today.
With CocoaPods all you have to do is describe which are your project dependencies and execute a command so that the manager search for each library and its dependencies, installing all of them in the project afterward. By doing this, the dependencies between the libraries are not an user responsible anymore and we can keep components updated more easily.
The installation is simple: install the Gem cocoapods so that you can use the tools. More details can be found on the project page at github.
The creation of components (Pods) is also simple: you just need the source in a git or svn server and then create a spec file about this source. It is possible to specify components as open source or as a Static Library.
We have some CocoaPods pros and cons:
Pros
- - version control;
- - library interdependence management;
- - easy to use;
- - separation between project and components;
- - easy to debug.
Cons
- - recent project with some bugs;
- - many libraries non available yet.
Being a recent project has some downsides, so CocoaPods still have some bugs and also there aren’t many libraries specs already available to Objective-C, but every developer can create them and contribute with the project development. Also, after the acceptance of your first specs they give you write access to the repository so that you can quickly contribute.
Now we are working with CocoaPods to manage the dependencies of our projects with a modified repository of specs to include our internal components, but it is a subject for another post.
This post has a portuguese version – “Como organizar e controlar versão dos seus componentes iOS”