iOS
How to Get Started With Pods
Matt Neuburg
Written on September 17, 2020

Pods, also known as CocoaPods, are a necessary evil. And they are ubiquitous. Even if you’ve never used them, you probably know that they exist, and you may even have a general sense of what they are, because questions about them come up on Stack Overflow all the time. Basically, Pods are code libraries that you use in your project, along with a mechanism for rationalizing versioned dependencies amongst themselves.
When you’re at GitHub looking for a code library, you are very likely to see ReadMe instructions like this:
To install MyCoolLibrary with CocoaPods, add this line to your Podfile…
That means that if you want to use this library, you’re probably going to have to use it as a Pod.
Now, before we go any further, let’s get it out in the open: Pods are the work of the devil. They are a terrible mechanism for installing libraries. They do terrible things to your project. They are an absolute horror.
But for a long time, they have been the only real choice. If you want to incorporate someone else’s self-contained code library into your project in a clear, maintainable way, how are you going to do it? You might consider copying the library’s actual code files into your app target; but that might not be possible, or might be unacceptable for various technical or legal reasons, and in any case it isn’t going to help you with problems of versioning and dependencies.
Recently, Apple has jumped on the open source library bandwagon with Swift Packages, which became available in Xcode 11. This mechanism, too, handles versioning and dependencies; and Swift Packages are installed in a way that doesn’t pollute your project. New in Xcode 12, Swift Packages can include resources and localizations. So it looks like they are well on the way to replacing CocoaPods as the package manager of choice.
Nevertheless, let’s just accept for now that sooner or later, you have to install a Pod into your project. If you’re like me, the way this happened is that you’ve been called upon to help write some code in a pre-existing project, and that project already uses Pods. So you just have to use them, whether you like it or not. And now you’re sitting there with your mouth hanging open, with no clue about how to get started; and you don’t want the others on your team to know that you are completely clueless. If you’re like me, that is.
And so you go online and start googling to try to find a tutorial or a set of instructions that is clear, correct, up-to-date, telling you how to get started with Pods. And if you’re like me, you can’t find one.
Well, that’s why I’m here now. I’m going to tell you, as if you are a complete neophyte, how to get started with Pods.
Rationalizing Ruby
CocoaPods are themselves installed and configured using yet another code library — a code library written in Ruby. In Ruby, a code library is called a gem. So the second thing you’re going to have do in order to get started with CocoaPods is to install that gem into your Ruby.
The reason that’s the second thing you’re going to have to do is this: before you can do anything in Ruby, you need to get control of your Ruby installation.
Here’s the problem. Mac OS X comes with a Ruby installation. And it sucks. Big time. First of all, it’s not up to date. Second, there’s no way bring it up to date, because it’s part of the system — it’s in /System/Library/Frameworks/Ruby.framework. Not only that, but anything you install into this Ruby is also part of the system: it goes into /Library/Ruby, and you can only perform such an installation by saying sudo
, which you can do only if you are a sudoer. This is an atrocious situation, and Apple knows it — and that’s why they have announced that, going forward, there won’t be any built-in Ruby installation. You’re going to be on your own. If you want Ruby at all, you’re going to have to install it yourself.
What you need to do, then, is to provide your own Ruby installation. And you need to provide it in such a way that it effectively overrides the built-in Ruby. That’s not easy to do if you try to do it on your own. Fortunately, you’re not on your own. There are some great mechanisms for installing your own Ruby, possibly more than one version of Ruby simultaneously. The main ones are rbenv
and RVM. The one that I use is rbenv
, and that’s the one I’m going to talk about now. If you’ve already got your Ruby under control, you can skip the rest of this section.
Install Xcode Tools
First, before you do anything else, make sure your developer command-line tools are correctly configured. If necessary, go to https://developer.apple.com/download/more/ and download the Command Line Tools corresponding to your Xcode version and run the installer. Also, in Xcode, open the Locations pane of the Preferences window, and use the Command Line Tools pop-up menu to point at this copy of Xcode. (You’ll have to give your admin username and password when you do that.)
To check that things are correctly set up, in the Terminal, say this:
% xcode-select -p
The result should be something like this:
/Applications/Xcode.app/Contents/Developer
In other words, we should be pointing into the Developer folder inside the Xcode that you are actually using.
Install Homebrew
We now want to install rbenv
. When you go to https://github.com/rbenv/rbenv for instructions, you find that they suggest using brew
. That means Homebrew. Have you installed Homebrew? Is it up to date? In the Terminal, type this:
% which brew
You should see this:
/usr/local/bin/brew
If you do, then type brew update
to make sure you’re up to date. If you see nothing, you need to install Homebrew from scratch. Go to https://brew.sh and do exactly what it says: they give you a line of bash code that you copy and paste directly at the Terminal prompt (and hit Return).
% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
You’ll be asked for your password, and brew
will be installed.
WARNING: My experience is that installation of
brew
is simple in a new clean admin user account, even in Catalina. However, older accounts may encounter permissions issues. Dealing with these is beyond the scope of this discussion.
Install Ruby
It turns out that rbenv
is present as part of your brew
installation. But you still don’t have an actual copy of Ruby! To confirm that fact, say this:
% rbenv versions
If all you see is system
, you need to install a version of Ruby. To find out what versions there are, say:
% rbenv install -l
You’ll see a huge list, but the one you want is the last one with no prefix and no suffix. For example, at this moment, in the middle of the list, I see this:
2.6.0-preview3
2.6.0-rc1
2.6.0-rc2
2.6.0
2.6.1
2.6.2
2.6.3
2.7.0-dev
jruby-1.5.6
jruby-1.6.3
The last version with no prefix and no suffix is 2.6.3
. That’s the current version of Ruby! So that’s the one we want. So say:
% rbenv install 2.6.3
Downloading and installing Ruby takes quite a long time, so go do something else for a while.
The result is two-fold. First, you do now have Ruby 2.6.3 — though you are not yet using it. Second, a folder called .rbenv has been created in your home directory. (This folder is normally invisible because its name starts with a dot.) This is where your new Ruby is going to live.
Configure rbenv
Now that you have Ruby 2.6.3, you need to start using it instead of the built-in Ruby. To do so, say:
% rbenv global 2.6.3
You should also tell rbenv
to clean itself up:
% rbenv rehash
That’s good, but you still need to ensure that this version of Ruby, managed by rbenv
, stands in front of the system Ruby. To find out how to do that, say
% rbenv init
This doesn’t actually do anything; instead, it tells you what to do. In particular, you’re going to need to modify your shell’s initialization script file; you’ll be told what that file is called and how you need to modify it. For example, if you’re using bash
as your shell, you’ll be told:
# Load rbenv automatically by appending
# the following to ~/.bash_profile:
eval "$(rbenv init -)"
And if you’re using zsh
, you’ll see this:
# Load rbenv automatically by appending
# the following to ~/.zshrc:
eval "$(rbenv init -)"
So do that! The easy way, which works regardless of whether you actually have an initialization script file, is to use echo
and the append operator >>
. So, for example:
% cd
% echo 'eval "$(rbenv init -)"' >> .zshrc
When that’s done, quit the Terminal. The point is that the next time you launch the Terminal, your shell will execute the line you’ve just created in its initialization script, and you’ll be using the Ruby you installed into rbenv
. To prove that you’re using it, just ask about Ruby:
% which ruby
/Users/you/.rbenv/shims/ruby
% ruby --version
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin19]
Getting the gem
Now that you’re in control of your own Ruby installation, you can install the Ruby gem that implements CocoaPods:
% gem install cocoapods
Again, tell rbenv
to clean up:
% rbenv rehash
Not only have you now installed a Ruby gem; you’ve also installed an associated command-line tool, namely pod
. To see this, ask where it is:
$ which pod
You should see something like this:
/Users/you/.rbenv/shims/pod
That proves that you have the pod
tool and that it’s in the right place, namely, inside your rbenv
installation.
Some tutorials at this point suggest that you also say pod setup
, but I don’t see any particular need for that.
Add a Pod
At long last we’re ready to add our first Pod to an actual Xcode project! Start by making a project. This can be a plain vanilla Xcode project drawn from any of the templates, such as the Single View App template.
Let’s say we want to incorporate the SnapKit Pod into this project. I’ve picked SnapKit pretty much at random; it can be anything. (To find out more about SnapKit, go to https://github.com/SnapKit/SnapKit.)
So let’s go for it! Here’s what to do.
First, quit Xcode. That’s right, quit Xcode. Pods work by performing horrible surgery on your project. Your project cannot be open during that surgery, and the best way to ensure that is to quit Xcode altogether.
Second, whip out any text editor. I like BBEdit but you can use anything you like. Make a new text file and save it into your project folder, using the filename podfile — just that, podfile and no more. Look at the file in the Finder! Make sure you have not accidentally added a .txt suffix.
Still editing your podfile text file, give it this content (I’m assuming you’re targeting iOS 13, which is more or less current as of this writing):
platform :ios, '13.0'
target 'MyProject' do
use_frameworks!
pod 'SnapKit'
end
That’s Ruby code! The reason is that the CocoaPods mechanism, which runs in Ruby, is going to find this file and load and execute it.
Once you’ve made the podfile contain that code, you can quit your text editor.
And now, the moment of truth. Open the Terminal and cd
into your project folder. (As you probably know, the easiest way to do that is to type cd
and a space at the command line, then drag the project folder from the Finder right onto the Terminal window, and then, in the Terminal again, hit Return.) And now say the magic words:
% pod install
The result is that your original project has been modified in horrifying ways. As the message in the Terminal informs you, this project is no longer your own. Let’s say your project is called MyProject.xcodeproj. Well, you can forget about that file from now on. You must open your project using a different file, MyProject.xcworkspace, which has been created for you. I strongly recommend that before doing that, you delete the contents of DerivedData.
Okay, are you ready to open MyProject.xcworkspace? Locate it in the Finder and double-click it to launch Xcode and open the project window. As you can see, your workspace now contains two projects, your own MyProject and a newly added Pods project. Moreover, your MyProject has been sullied with a Pods group and a Frameworks group. There’s nothing you can do about that all; it’s just how Pods work.
The outcome is that your code (in MyProject) can import SnapKit
and use SnapKit classes and methods. That was the goal. You’ve installed a library as a Pod.
Starting over
Sometimes you need to uninstall the Pods from your project and start over. The way to do that is, having quit Xcode, to cd
into your project folder and say:
% pod deintegrate
This removes the Pods from your project. But it leaves the podfile in place, so if you now say pod install
again, you have effectively started over. Sometimes, that sort of cleaning is just what you need.