A review of iOS dependency managers

Introduction

If you have ever worked on an iOS project of moderate complexity you have had to deal with integrating third-party dependencies. As of mid 2016 you have three options: CocoaPods, Carthage, or by hand.

There is also Xcode Maven and Xcode Gradle but they require a lot of work up front, they don't have a large iOS community (you are on your own) and they are geared towards Java. We will leave them out for now. There is also the Swift Package Manager, but as or mid 2016 it doesn't support iOS.

In what follows I am going to give a quick summary of each system and follow that with a list of pros and cons. Then I will share some of my best practices and future directions.

CocoaPods

CocoaPods is the de facto standard of package management for iOS. It has the largest community and is officially supported by almost every open-source iOS library.

Pros

  • Large community. If you have a problem there is going to be someone who already had that problem. It is very unlikely you are going to run into something that no-one knows how to fix.
  • Large number of available libraries with official support. This means you will likely get timely updates and it will work across different versions of Xcode and iOS.
  • Stable. It is already at version 1.0+, you can assume there are not going to be breaking changes in the foreseeable future.
  • Solid dependency resolution. This is in contrast to Carthage, see below.

Cons

  • Invasive. Some people find CocoaPods' modification of their Xcode projects invasive.
  • Centralized. There is a single central project repository. If it goes down or gets rate-limited you will be affected.
  • Two-step process for working on dependencies. If you have dependencies on which you want to work on in parallel you have to switch them to development pods, make your changes, test, then switch back, then make sure you tag and keep your Podspecs and Podfiles up to date. In my opinion this is the biggest con.

Carthage

Carthage was created as a decentralized alternative to CocoaPods. As opposed to CocoaPods, Carthage doesn't require explicit support from a library and it doesn't rely on a central repository.

Pros

  • Non-invasive. Carthage fetches and compiles your dependencies but it is up to you to integrate those with your project.
  • Decentralized. There is no single point of failure. Your dependencies are fetched from their original repositories.
  • Supports submodules. In my opinion this is the biggest pro. By using submodules you can make changes on your dependencies without any extra steps. When you are done just make sure you commit on the submodules as well as the main project.

Cons

  • Unstable. It currently has some serious stability problems. In my personal experience it hangs often; it currently has a bug where it hangs if it fails to resolve a dependency.
  • Slow. It is very slow, especially if you have a large dependency graph.
  • Small community. More and more people are starting to use it, but there are not many people contributing.
  • Inflexible. It is opinionated on how your build process works. For instance you can't change the location of the built frameworks or the location of the submodules.

Roll your own

You don't have to use a dependency management system, especially if your project only has a few dependencies. You can drop the code in your project, or drop a pre-compiled binary, or use git submodules, or write your own script. Whichever way you go it's going to requite some effort on your side to keep up to date with the latest versions and to ensure compatibility with newer versions of the dependencies and the build system.

Pros

  • Flexible. You can do whatever you want!

Cons

  • Hard to keep up to date. You need to make sure you script works with the latest version of Xcode and you need to keep track of all the dependencies.
  • Potentially fragile. If a dependency changes the layout of their sources you may need to adjust your build instructions.

Conclusions

Dependency management in iOS is ages behind the situation in other platforms. The problem is in part the lack of official support in the tools but also the fact that it is an environment that changes quickly (Swift, lack of binary compatibility, etc.). I look forward to the official release of the Swift Package Manager but in the mean time here are some pointers if you need to decide on a dependency manager.

If you don't plan on modifying your dependencies while you work on your main project go with CocoaPods. It is stable and well supported and the fact that it modifies the project should't be a problem in most cases. This is specially true if you have many dependencies.

If you have a project that is split into separate pieces and you often modify those pieces the situation is not as clear-cut. One option is to go with Carthage with submodules. You may find yourself waiting for a long time every time you do carthage update and it may fall apart as your dependency graph grows. Another option is using CocoaPods with development pods. The problem with this is that you will end up switching back and forth between pointing to a development location and pointing to a specific tag. And running pod install in-between.

There is currently no good solution for this particular problem. I created a feature request on CocoaPods. But a more stable Carthage would also be a good solution. What is your take on this?