A Tale of Package Managers | Xcode Project Setup Series
A brief analysis of the main package managers for Xcode projects
What is a package manager?
A package manager is a tool that automates the process of installing, upgrading, configuring, and removing libraries.
What are the main package managers that you can use with Xcode?
The main package managers that you can use with Xcode are:
- Swift Package Manager (SwiftPM or SPM)
- Cocoapods
- Carthage
Swift Package Manager
SPM is a decentralized package manager and makes heavy use of Git. Xcode offers an option to initialize a local Git repository when we create a package: You can initialize the Git repository when creating a package.
While tools like CocoaPods require Ruby and other Gem dependencies, there’s no need for SPM. SPM, on the other hand, requires either Swift 3.0 or Xcode 10 and above to be installed on your macOS or Linux machine.
It works on all Apple platforms, iOS, tvOS, watchOS, and macOS.
CocoaPods
CocoaPods is a centralized dependency manager for Swift and Objective-C Cocoa projects. It is open-source and was built with Ruby. It does a whole lot behind the scenes to make everything work.
On a relatively high level, the actual ‘Pods’ are managed in a repo that lives on GitHub here. This is where 3rd party library vendors submit their ‘Pods’ to work with CocoaPods. You’ll notice that if you search for a Pod using the command line tool with pod search AFNetworking
you will see all the available Pods matching your search term.
It works on all Apple platforms, iOS, tvOS, watchOS, and macOS.
Carthage
Carthage is a decentralized dependency manager for Swift and Objective-C Cocoa projects. It is open-source and built with Swift.
Being decentralized reduces maintenance work and avoids any central points of failure, but project discovery becomes more difficult. For example, checking for outdated dependencies means checking every dependency repository instead of a single centralized one.
It differs from the other two package managers, described in this article, as it requires the developer to do some or quite some manual work.
Which one(s) should you use?
This comes down to the specific needs of the project you are working on. As a general rule of thumb, if you are not forced for any particular reason to use Cocoapods or Carthage, I strongly recommend you go with SPM.
Before even using a dependency manager, what I did in my early days when coding on Xcode was not to use one at all. Try to add libraries, frameworks, and projects to an existing one. Doing so, for a while, will force you to understand what is going on underneath.
As a next step, install Cocoapods. This time, download all, or part of, your previously manually added libraries, frameworks, and projects using Cocoapods. At this point, depending on how much time have and the complexity of your project, you will have a good understanding of how the dependency managers work.
I suggested earlier that you try Cocoapods on purpose, as compared to the other two, it does a lot more of the magic (work) behind the scenes. Before you heavily make use of Cocoapods I would recommend having a closer look at how it works and what it does underneath.
Use more than one dependency manager
At a certain point, you might need to use a legacy library or more than one. It is not that uncommon that legacy libraries are not being updated to SPM for a long time or worse they are not maintained anymore.
In this case, you are left with a couple of options.
- Manually add the library to your project
- Use another dependency manager that is supported
- Create a Swift package binary as an XCFramework bundle
Again, personal opinion, go with the third option. It might take slightly longer to learn and implement but it will pay off in the long run.
Limitations on using more than one dependency manager in a project
Besides my efforts to convince you otherwise you decide to go with the multiple dependency managers. 🙂 Great! In most cases, you won’t have any issues using more than one dependency manager in a single project. Also, mix-and-match libraries won’t be an issue either. Except in a single dependency chain
Let me elaborate on the last sentence.
You add library B from Cocoapods. Let’s suppose that library B has a dependency on library A. Also, let’s assume that another library C was added using SPM and it also has a reliance on library A.
The “issue” or one thing to take away from this case is that library A will be brought twice in your project, once from Cocoapods and once from SPM. Having a small amount of fairly small libraries won’t be an issue, probably. On large projects, probably yes, as you will end up with a lot of copies of the same library(ies).
Food for thoughts:
The first time I came against this issue, I started wondering about performance and memory optimization. What is your take on this matter?
In Conclusion
Following the same logic as with code refactoring engineers/programmers should pay more and more attention and effort on package dependency refactoring or at least explore the options and pick the most suitable one.