How To Manage Dependencies With CocoaPods

CocoaPods is a dependency manager for Cocoa projects. There are a handful of alternatives, such as Carthage and the Swift Package Manager, but CocoaPods is the most popular one. CocoaPods makes managing dependencies easy and transparent.

Eloy DurĂ¡n started with the development of CocoaPods in 2011. With his background in Ruby, Eloy was inspired by Bundler and RubyGems. If you're familiar with Bundler and RubyGems, then you won't have much difficulties understanding the concepts on which CocoaPods is built.

In this episode, you learn everything you need to know to get started with CocoaPods.

Installing CocoaPods

CocoaPods is written in Ruby and distributed as a gem. Gems are best installed using RubyGems, a package manager for Ruby. Ruby and RubyGems should already be installed on your machine if you're running a recent version of macOS.

Open Terminal or iTerm and execute the gem install cocoapods command to install CocoaPods.

gem install cocoapods

Depending on the configuration of your machine, you need to prefix this command with the sudo command.

sudo gem install cocoapods

I usually advise people to use a version manager for Ruby, such as RVM or rbenv. I have used both and have settled with rbenv. Both tools make it easy to switch between Ruby environments and they don't require you to use the sudo command to install CocoaPods.

Execute the pod --version command to make sure the installation of CocoaPods was successful.

pod --version
1.4.0

At the time of writing, CocoaPods 1.4.0 is the latest stable release of the dependency manager.

Project Setup

It's time to find out how CocoaPods can help us with Cocoa development. Open Xcode and create a new project based on the Single View App template.

Choose the Single View Application Template

Name your project and set Language to Swift.

Configure the Xcode Project

Tell Xcode where you want to save the project and click Create. Close the project and open Terminal or iTerm.

Setting Up the Podfile

The beauty of CocoaPods is that you list the dependencies of your project in a central location, the project's Podfile. CocoaPods refers to a dependency as a pod hence the name Podfile. Because CocoaPods took inspiration from Bundler, the syntax and format look similar to that of a Gemfile.

You can manually create a Podfile with a text editor or execute the pod init command at the root of your Xcode project.

pod init

This command creates a Podfile at the root of your Xcode project. Open the file in your favorite text editor. I am using CocoaPods 1.4.0 and this is what my project's Podfile looks like.

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'Notes' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Notes

end

The syntax of the Podfile may look foreign if you're not familiar with Ruby. Don't worry, though. You don't need to understand a word of Ruby to use CocoaPods. The CocoaPods documentation is excellent.

Lines that begin with a hash symbol are comments. The first comment tells us that we can uncomment the second line to tell CocoaPods that we target the iOS platform and that the deployment target of the project is iOS 9.0. This is what we end up with if we remove the first comment and uncomment the second line.

platform :ios, '9.0'

target 'Notes' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Notes

end

In Ruby, a block is a chunk of code that start with the do keyword and ends with the end keyword. This is similar to the opening and closing curly brace in Swift and Objective-C.

A target block corresponds with a target of the Xcode project. Notice how CocoaPods has already created a target block for the Notes target of the Xcode project.

By using a target block, we can define the dependencies for the corresponding target of the Xcode project. Within the target block, we encounter a few more comments and a special attribute.

The use_frameworks! attribute tells CocoaPods that the target uses dynamic frameworks instead of static libraries. This is important if you're using Swift. This is what we have so far if we remove the comments in the target block and leave the use_frameworks! attribute as is.

platform :ios, '9.0'

target 'Notes' do
  use_frameworks!
end

Defining Dependencies

Defining the dependencies of your project is very easy. Every dependency begins with the pod keyword and is followed by the name of the dependency, wrapped in single or double quotes. You can optionally specify the version of the dependency.

platform :ios, '9.0'

target 'Notes' do
  use_frameworks!

  pod 'Fabric'
  pod 'Alamofire', '4.6.0'
  pod 'CocoaLumberjack', '~> 3.4'
end

Because we don't specify a version for Fabric, CocoaPods will use the latest version that is compatible with the platform and deployment target we specified earlier.

For Alamofire, a networking library, we explicitly set the version to 4.6.0. We also specify the version of CocoaLumberjack, but we use the ~> symbol to indicate that CocoaPods can use any version starting from 3.4 and ending at 4.0, excluding 4.0. The ~> symbol is very useful if you want to update a dependency, without accidentally installing a version that introduces major or breaking changes.

There are several other symbols you can use to specify the version of a dependency, >, >=, <, and <=. Their meaning isn't difficult to understand.

Installing Dependencies

Now that we have listed the dependencies of the target, it's time to install them. Save the changes you made to your project's Podfile and open Terminal or iTerm. Execute the pod install command to install the dependencies you defined in the project's Podfile.

pod install

If you want to know exactly what CocoaPods is doing behind the scenes, you can add the --verbose flag. This is the output I see without the --verbose flag.

pod install
Analyzing dependencies
Downloading dependencies
Installing Alamofire (4.6.0)
Installing CocoaLumberjack (2.4.0)
Installing Fabric (1.7.2)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `Notes.xcworkspace` for this project from now on.
Sending stats
Pod installation complete! There are 3 dependencies from the Podfile and 3 total pods installed.

Even though you don't need to understand every step of the process, it's useful to have an idea of what's going on. CocoaPods maintains a list of every dependency available through CocoaPods and it keeps a local clone of that list on your machine. You can find it at ~/.cocoapods/repos/master. Before it installs the dependencies, it pulls in any changes from GitHub to make sure the list is up to date.

CocoaPods then inspects the list of dependencies in your project's Podfile. It ensures the dependencies you specified are compatible with your project and its targets. It also checks that none of the listed dependencies conflict with one another. After downloading the dependencies, it installs them in a Pods directory at the root of your Xcode project.

CocoaPods creates a Pods project and a workspace in which it places your project and the Pods project. Note that CocoaPods tells you to use the workspace, Notes.xcworkspace, from now on. If you don't, you won't have access to the dependencies you installed through CocoaPods.

This is what the project folder looks like after running the pod install command.

This is what the project folder looks like.

Using the Dependencies

Fire up Xcode and open Notes.xcworkspace, the workspace CocoaPods created for you. Notice that the workspace contains your project as well as the Pods project.

Open the CocoaPods Workspace

This is one of the features I enjoy most about CocoaPods. It clearly separates your project from the project's dependencies. In addition, CocoaPods configures your project based on the needs of the dependencies you listed. It just works ... well ... most of the time.

Build the project to make sure you don't run into any errors or warnings. Depending on the version of CocoaPods you're using, you may need to update the project's settings.

Let me prove that CocoaPods has done its job by fetching the CocoaPods logo and displaying it in an image view. Open Main.storyboard and add an image view to the View Controller Scene. Declare an outlet in ViewController.swift and connect the image view to the outlet in the storyboard.

In ViewController.swift, add an import statement for the Alamofire library and fetch the CocoaPods logo in the viewDidLoad() method of the ViewController class.

import UIKit
import Alamofire

class ViewController: UIViewController {

    // MARK: - Properties

    @IBOutlet weak var imageView: UIImageView!

    // MARK: - View Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        Alamofire.request("https://avatars3.githubusercontent.com/u/1189714?v=3&s=400")
            .responseData { (response) in
                DispatchQueue.main.async {
                    if let data = response.data {
                        self.imageView.image = UIImage(data: data)
                    }
                }
        }
    }

}

It's a rough implementation, but it illustrates that we have access to the Alamofire library we included using CocoaPods.

Donwloading the CocoaPods Logo

Updating Pods

Another marvelous feature of CocoaPods is the ease with which you can update dependencies. Before CocoaPods was around, you'd have to download and update your project's dependencies manually. Updating dependencies with CocoaPods requires two steps:

  • update the Podfile
  • execute the pod update command

Update the project's Podfile by removing CocoaLumberjack from the Podfile and lowering the version of Alamofire.

platform :ios, '9.0'

target 'Notes' do
  use_frameworks!

  pod 'Fabric'
  pod 'Alamofire', '4.5.1'
end

Open Terminal or iTerm and run pod update to update the project's dependencies.

pod update
Update all pods
Updating local specs repositories
...
Analyzing dependencies
Removing CocoaLumberjack
Downloading dependencies
Installing Alamofire 4.5.1 (was 4.6.0)
Using Fabric (1.7.2)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 2 dependencies from the Podfile and 2 total pods installed.

CocoaPods updates Alamofire to version 4.5.1 and it removes CocoaLumberjack. That's all it takes to update dependencies with CocoaPods.

Finding Pods

How do you know which libraries are available as pods through CocoaPods? The answer is simple, visit the CocoaPods website. The website shows a large search field. Start typing to search for the library you're looking for and the CocoaPods website shows you any matches it can find.

Searching for Pods With CocoaPods

What's Next

We only covered the basics in this episode. You're now able to integrate CocoaPods in your development flow. CocoaPods has a lot more to offer, though.