CocoaPods vs Carthage - Part II

carthage   cocoapods   iOS  

Recently I penned a post about what I went through getting CocoaPods going on a project recently vs what would be the case if the project had used Carthage. I suspected it might provoke some discussion and it did. Those who disagreed with my post mostly put forth several core themes:

  • That the problems I had with CocoaPods where caused by me not having my system already setup.
  • That I had not used CocoaPods correctly.
  • That I was only looking at one aspect of CocoaPods which I cast in a negative light.

I was also asked about a more general coverage of the CocoaPods vs Carthage debate.

Now I’ll say straight up that my personal opinion is that Carthage is a better dependency manager than CocoaPods by a long margin.

This is a very high level and to some - quite a provocative statement. But like any 'off the cuff' opinion there are caveats attached. ie. When looking at CocoaPods and Carthage in detail, there are some features where CocoaPods is better than Carthage, others where Carthage is better, and some that are simply a draw.

But when I look at all the features I’ve used of both - I regard Carthage’s solutions to be generally better than CocoaPods. Most especially in those features that matter to me.

Ok, so what makes something better?

I weigh up tools and APIs based pretty much on two criteria. How much effort I have to do to use it? and How much does it do for me?

Requiring little effort means I don’t have put much time or thought into using it. Tools and APIs which require little effort always feel intuitive and easy to use. I don’t want to be spending a lot of time editing support files, or mentally context switching, or constantly referring to it’s documentation every time I have to deal with something. I want to spend my time concentrating on my app.

Generally speaking, the effort to use a tool or API must be less than the effort required if I don’t use it. The ideal tool being one that requires little work to use whilst providing a large amount of functionality. At the other end of the scale, if a tool or API requires more effort than not, it’s clearly not worth using.

I also use the same criteria when weighing up one tool against another. So the tool that requires the least effort for the maximum functionality will win over one that requires more effort or provides less functionality.

But lets get back to CocoaPods and Carthage.

Having clarified ( I hope) how I look at things, lets go through a whole bunch of things a developer needs an Xcode dependency manager to do and see how they fair in my opinion and why.

Setting up

I’ve pretty much covered this here. CocoaPods has dependencies on you having Ruby, a whole bunch of Gems and your system configured to the correct versions. Not everyone has this and it can take some time and technical knowledge to to get everything working smoothly. People who use Ruby a lot are probably not going to have problems with this. But not everyones uses Ruby and some of the errors you get can be quite arcane. Using one or more of the available Ruby dependency managers can help, but having to use a dependency manager to setup a dependency manager kinda raises some red flags with me.

Carthage is a single download of a standard OS X DMG installer containing a single OS X native command line program.

For those of you who are interested: CocoaPods is written in Ruby. Carthage is written in Swift.

Winner: Carthage - Only if you already have the right version of Ruby and various Gems, can CocoPods be as easy to setup as Carthage.

Dependency sources

CocoaPods is dependant on a single repository in GitHub where every known pod is referenced. Before CocoaPods can do anything, it must download a copy of this central repository to your drive. To obtain a dependency it looks up a podspec in this repository which defines where to get the source code, what it supports and a bunch of other stuff.

CocoaPods supports dependencies specified as included source code, static libraries, dynamic frameworks and pre-compiled binaries.

Carthage uses a decentralised model which means you need to know where to get your dependency from in order to specify it to Carthage. Currently Carthage can locate dependencies on GitHub or any git server you can access, and also from the local file system.

Carthage supports dynamic frameworks and pre-compiled binaries as dependencies.

Winner: Carthage - or CocoaPods if you require static libraries. But Carthage because it’s decentralised model is simpler and faster.

Support

CocoaPods has been around for quite some time and therefore just about every third party API supports it.

Carthage has only been around for a short time and there are still quite a number of third party APIs which have not made the changes necessary to support it.

Winner: CocoaPods - For the moment. But Carthage support is increasing quickly due to the simplicity of adding it.

Defining dependencies

CocoaPods requires you to define a file called Podfile which is where you configure how CocoaPods integrates with your project. You may also have to define another file called Gemfile to set the version of CocoaPods and other gems.

CocoaPods configuration can be as simple as entering a single line per dependency. However the Podfile can turn into a complex setup definition outlining all sorts of modifications to your projects build and settings. If you have to go to this level of complexity (and it happens quite often) you will invariably spend quite a bit of time in the CocoaPods documentation working it out.

Carthage requires you to setup a file called Cartfile which is where you configure the dependencies it will manage. Each dependency requires just a single entry in the Cartfile specifying where the dependency comes from and the version.

Winner: Carthage - Because it does this so simply.

Integrating with your project

CocoPods uses a simple shell command to add it to your project pod install. This will do a number of things:

  • Create or modify an Xcode workspace. You must use this workspace when working on a project which uses CocoaPods.
  • Add a new project call Pods. This project contains all the pods you have specified as dependencies and all of their dependencies. There can be a large amount of stuff in this project. From downloaded binary frameworks to complete copies of a dependencies source code.
  • Creates a number of xcconfig files and attaches them to your builds. These xcconfigs specify all sorts of build settings which modify your built targets and configurations to include the CocoaPods dependencies from the Pods project.
  • Add new build phases to to your targets to check the state of the CocoaPods sandbox, copy the pods frameworks and copy any required resources.

Carthage does not directly modify your project or workspace or impose any settings or configurations.

Once you have initially built your dependences using carthage bootstrap, you can go to it’s build directory (e.g. ./Carthage/Build/iOS) where you will find all the built framework files. You simply add them to your project as you would any other framework.

Due to a bug in the app store submission process, Carthage requires one extra build phase to copy the built frameworks into your compiled app. This phase runs the carthage copy-frameworks shell script and you need to pass it a list of the frameworks you have built. If this bug gets fixed at some time in the future, this step will no longer be needed.

Winner: Carthage - Simply because it’s so light in terms of integration, it’s almost invisible.

Building your project

CocoaPods builds all dependencies as part of building your project. Normally this only happens the first time you build. However if you clear your derived data path or project build directories, then the next build will need to rebuild all dependencies again.

Carthage only build dependencies when you expressly tell it to from a command line. Thereafter the built frameworks are always present. Clearing the derived data directory does not effect this.

Winner: Carthage - Because it only builds when you want it to.

Working with your code

One thing that you will notice when working on a project that uses CocoaPods is that because all the source code for all the dependencies are added to the workspace you have to use, you inherit all of their compiler warnings and output in Xcode. Plus when doing things like searching your code base, you have to remember to setup searches so that they avoid the source of the dependencies. Something to be careful of when doing a search and replace.

Because Carthage does not include the dependency projects and compiles then independently of Xcode, the only code in your project is the project’s own code.

Winner: Carthage - Because it doesn’t add any extra noise to your IDE.

Updating your project

Adding, editing and deleting dependencies.

Updating CocoaPods can be simple or complex. It’s going to totally depend on the nature of the update and whether there are complications which need to be added to the Podfile. Afterwards you will need to execute pod update to modify the Pod workspace. Because of the potential complexities of the Podfile, this may need to be done several times and involve spending time on the CocoaPods documentation site working out what needs to change.

Carthage simply requires changes to be done to the Cartfile and carthage update to be executed. If you are simply modifying the version of a dependency or switching to a different branch in the source you don’t need to modify your project, the modified frameworks will be automatically picked up. Additions of new dependencies or removals will require you to add or remove the matching frameworks from you project manually.

Winner: Carthage - Again because of the simplicity of it’s configuration and how it works.

Speeding up the startup

When you check out a CocoaPods project, the authors have the option to include the entire Pods directory. This will obviously save startup time, however I’m not sure at this point (having never done this) if you would still need to download the central CocoaPods repository if you don’t already have it.

With Carthage, the project authors have the option to check in the ./Build/Checkouts directory and Cartfile.resolved file. With these two things present, no further downloads are required.

Winner: None/both - it’s a draw

IDE support

The CocoaPods team recently released a CocoaPods editor/ standalone IDE for editing your Podfile and running pod commands. This can take some of the pain points out of using CocoaPods.

Carthage does not have any app or IDE plugins as yet and there does not appear to be any plans to do one.

Winner: CocoaPods - Although I’m not sure being complex enough to warrant your own IDE is really a win.

CI Integration

Having been around for a while CocoaPods has quite extensive integration and support from various CI servers and build tooling. There’s too many to cover here so just check out the doco and plugins for your favourite. Apart from the obvious possibility of issues around installing CocoaPods on the CI server, I’m not aware of any other issues.

Carthage being the newer tool is still gaining support. The only complication I am aware of is that your CI scripts will have to do carthage bootstrap (or carthage build if you have the checkouts directory checked in) as the first step in order to get the frameworks built.

Winner: None/both - it’s a draw

Releasing your own APIs

In order to release your own API as a CocoaPod pod, you need to first add a podspec file. The contents of this file are fairly involved and you will need to read the podspec documentation to work it out. I also found that the CocoaPods team have provided the pod lib lint command to validate the pod spec you have created.

To do the release, you have to publish your project to GitHub or some other repository. Then make use of the pod repo … series of commands to send your podspec file to the central podspec repository and manage it.

To be honest, I’ve only tried this once and gave up when the pod lib lint command kept throwing errors which appeared to be internal ones. I may go and try this again some time in the future.

To release an API with Carthage you first need to have your project available via GitHub or some other public repository. Then you need to have an Xcode shared scheme which builds your framework file. Carthage will do the rest. I’ve done this a number of times and it’s so easy it’s almost instinctive.

Winner: Carthage - There’s really no comparison here.

Summary

I hope that this clarifies why I think Carthage is the better of the two tools. I’m sure there are people who will disagree and that’s ok. But at the moment, after having used both across a number of projects for home and work, I cannot think of any feature of CocoaPods that would incline me to use it.


Comments powered by Disqus