Benedict's Soapbox

Managing Any Dependancy using Cocoapods (A.K.A. Cocoapods and git submodules up a tree...)

Cocoapods has become the defacto dependancy management system for iOS and Mac development. Cocoapods success is undoubtably due in part because it solves genuine problem and it does so elegantly. Cocoapods, however, is not without its’ flaws. My gripes with Cocoapods are:

Theses two issues significantly undermine(d) the usefulness of Cocoapods for me because if a dependancy manager can’t manage all my dependancies then it’s adding complication rather than removing it. I recent started a new project and wanted to finally find a solution to these problems. Thankfully I did and it’s surprisingly simple…

(Sidenote/micro-rant: Cocoapods performs 2 tasks; Xcode integration and management of external source code. I wish the architecture of Cocoapods made a clearer separation between these 2 tasks.)

Integrating dependancies that don’t have a podspec

The trick here is to treat the dependancy as a ‘development pod’. This is done by creating a minimal podspec for the dependancy and referring to it from the podfile file using :path. (Using :path also causes Cocoapods to handle the source files differently which I’ll come back to later.) This is what the folder structure look like:

+ ProjectRoot
    | - project.xcproject
    | + Project
    |   | - ...
    | + Pods
    |   | - ...
    | - podfile
    | + Externals
        | + Dependancy
            | - dependancy.podspec
            | + DependancySource
                | - ...

The rest of the files and folders are just as you’d expect with a normal Cocoapods-managed project.

Contribute changes back to a project

This too is surprisingly simple to setup. As previously mentioned, there’s a side effect of using :path when specify ours pods. When using a podspec from a repo (which is the most common case) Cocoapods copies the source files into a sub-folder of the Pods folder. This means that we loose integration with the original VCS. But when using :path Cocoapods doesn’t copy the files, instead it simply references the original files. This means that changes made to the dependancy from within our Xcode project are performed on the original source regardless of where they’re stored. This makes it really easy to contribute changes upstream.

In the example listed above this can be achieved by managing DependancySource as a git submodule. Setting up a submodule is beyond the scope of this post so go google it. You may also want to investigate git subtrees. I’m no git expert but I think there are situations when a subtree may be more appropriate.