David Yang

Tips and posts for iOS developers from an iOS developer.

Both are dependency managers for Cocoa projects with a large community of users or contributors. In this article, I will first try to explain their common purpose and what sets them apart.

Why use a dependency manager?

But first, what is a dependency? A dependency is an external standalone program, a library or a framework. It is designed to be used in a larger application in order to achieve specific tasks.

You may know some of them, such as Alamofire, AFNetworking, MagicalRecord or SwiftyJSON…

Now let’s say you want to integrate such a library or framework in your iOS application, you could deal with it in different ways:

  • You could just import the dependency’s source files in your project (maybe the ugliest way to do)
  • Import the dependency as a seperate Xcode project into your own project or workspace.
  • Build a framework or a library and integrate it in your project
  • Or use a dependency manager… such as CocoaPods or Carthage, which would actually result in using one of the two previous ways

To define a dependency manager, it is a tool that enables integration of dependencies (libraries or frameworks) in an existing and larger application.

Now, let’s dive (but not too deep) into how it actually works…

CocoaPods

CocoaPods is made in Ruby. It is pretty easy to use: just install it on your computer with gem install cocoapods, add a Podfile at the root of your project (using the command line pod init) and declare your dependencies like this:

target 'MyApp'
pod 'Alamofire'

Then, you will just need to run pod install and let the magic work.

Here are the few things you need to know when using CocoaPods :

  • CocoaPods will download the sources of your dependencies and put them in a Pods project.
  • It will restructure your project by creating an Xcode workspace which will contain your application project and the Pods project (the dependencies).
  • You will have to use that Xcode workspace created by CocoaPods to be able to use dependencies.
  • It will add search paths for the Pods libraries or frameworks in your project settings.
  • It will add custom build phases in your project in order to build the dependecies before building your app.

Under the hood, CocoaPods works with a CocoaPods Spec repository: a simple Github repository containing podspec files, each one defining a public dependency and the versions made available by the community. This CocoaPods Spec repository acts as a central point to CocoaPods and a dependency catalog.

If you want to know more about CocoaPods, visit the official website.

Carthage

Carthage is written in Swift and have been released after CocoaPods. Although the setup is similar to CocoaPods, the integration works in a different way. First of all you will need to install it (brew install carthage), and then create a Cartfile and declare your dependencies as following:

github "Alamofire/Alamofire" ~> 4.7.2

Then, just run carthage update:

  • Carthage will clone the sources of your dependencies from Github and will build them with xcodebuild. It then provides you a built framework.
  • The user will have to manually integrate the dependencies manually to his existing Xcode project.
  • It will leave the sources from the download dependencies in a subpath of the working directory.

By letting the developer manually integrating the dependency to his project, it is less intrusive than CocoaPods which forces the project into a defined structure in order to work.

Another difference with CocoaPods is that Carthage is defined as a decentralized dependency manager. That means there is no catalog or central point listing all dependencies. You will have to research by yourself to know if the dependency you need support Carthage or not (usually by refering to its Github page).

For more details about Carthage, check the Github project page.

Rome

If I did not mention Rome earlier in my introduction, it is because it is actually come from the CocoaPods team. Obviously, it is their direct response to Carthage (you might want to check the Punic Wars if you missed the reference) and generates built frameworks.

Like CocoaPods, it is also made in Ruby but works in a very similar way to Carthage.

As it is not shipped with CocoaPods, Rome actually acts as plugin to it. In order to install it, you will have to enter the command line gem install cocoapods-rome.

Rome also works with a Podfile which gets a little heavier, as you will have to add the Rome plugin in a code-block before listing your dependencies:

platform :ios, '8.0'

plugin 'cocoapods-rome', { :pre_compile => Proc.new { |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            config.build_settings['SWIFT_VERSION'] = '4.0'
        end
    end

    installer.pods_project.save
},

    dsym: false,
    configuration: 'Release'
}

target 'MyApp' do
  pod 'Alamofire'
end

Unlike Carthage, Rome benefits the CocoaPods catalog, which makes it easy to look for a dependency and makes any existing Pod available with Rome.

If you take a look at their Github page, you may notice that the Rome community is not as large as CocoaPods’ or Carthage’s, but it still is worth knowing about it.

Now that you know more about CocoaPods and Carthage…

Which one should you use?

And my answer to this question will simply be: the one that fits your needs.

With my experience, here are some things to consider for each one of them.

  • Before integrating a dependency, ask yourself if you really need to. Are there features you really need from Alamofire/AFNetworking that you can’t easily do with URLSession?

  • If you plan working with a dependency manager for modularity within your app: is it really worth using a dependency manager rather than just integrating an external Xcode project to your project or workspace? Will you benefit from it?

  • With a built framework, you will only have access to the headers of your dependency’s source files.

  • With CocoaPods, you will have the entire source code of your dependencies in your workspace, which can be really helpful when debugging, using or developping frameworks.

  • Projects with built frameworks (Carthage/Rome) will obviously build faster! Because your project will not have to build the dependency.

  • Depending on your needs, you can use both Cocoapods and Carthage in your project. And you don’t have to be ashamed, it is totally fine!

  • Be careful, Carthage is open source only. And that is actually the reason why Firebase is not available with Carthage. But if you still want a built framework, Firebase is available with CocoaPods, which means it is with Rome too… Which means you can have a Firebase built framework.

  • If you plan to work on a graphical components library (obviously I did), features such as IBDesignable (custom views rendering in Interface Builder) are not available with built frameworks… You may prefer CocoaPods or an external Xcode project to do this.

  • Using any of these dependency managers with version control (GIT, SVN, etc), it is a good and safe idea to check in the Pods project or the sources used to build the framework: you never know when a dependency can disappear from Github.

Conclusion

Any choice is defendable. And it has to fit your needs as both solutions have pros and cons.

Personally, I prefer working with CocoaPods for a few reasons. The main one is probably that I like to be able to browse into a library’s source code in order to see how things work. And if I need to tweak things through an extension or category, it’s a lot easier. It’s also best suited for framework or library development in my opinion.

Finally, you don’t have to be afraid of CocoaPods because it is made with Ruby. You really don’t need that much knowledge with Ruby to make it work.