In this blog, I would give 7 reasons why I have reached a space where I don’t like Cocoapods anymore. To be clear I have nothing against Cocoapods, they have done great work on making iOS Developer's life easy for a decade. Also, it’s not just about Cocoapods, I feel the points I would highlight is true for any Dependency Manager.
Like any Developer, I would love to have 100% focus on my Development, but there are situations with Cocoapods which don’t let me do that. Instead, I have to fix some build issues which are sometimes sporadic & out of context.
There are few errors that can be solved with a quick search on Stack overflow like the ones below:
dyld: Symbol not found: SomeFramework referenced from App
dyld: Symbol not found: _OBJC_CLASS_$_SomeFrameworkClass
But, there are few errors that are so over our normal heads that we spend days fixing them. Sometimes Stack overflow & Github issues don’t help.
Two such examples are below. My team spent days on these even though we have a fair share of knowledge on iOS & Cocoapods.
Firebase framework preprocessor error
Firebase framework file not found error
The worst part is we did the same thing that most of us do in such situations, we switched back to a working version of: Library X.x, Xcode Y.y & Cocoapods Z.z
As a Team, when we go with Cocoapods, we like to think that we all are on the same page. But, is it really so?
There are few factors that are often ignored:
There are times when we unknowingly update the above versions. I think the most interesting way we do that is by
pod update instead of
pod install often without knowing the difference between the two.
Many of us especially young developers might feel cocoapod is doing some kind of magic. Is it really magic? or it’s more like a black box for beginners.
That brings us to the following questions:
frameworks.sh, which cocoapod creates internally for the whole thing to work. A one-year experienced Me would ask what is a
spec.static_framework = true. A one year experienced Me would ask what is a
I remember how we added some 20 MB to our App Size in my previous organization by just
spec.static_framework = true without even realizing it for a couple of weeks. I guess it was one of those things you do for Compiler ❤️
I know there is a choice to use it or not, also I am not advocating against it. All I am trying to say is, I feel it’s a Black Box for many of us.
I would also agree that it’s an easy way out. If that works for you, awesome. If not, try to DIY which will give you a better understanding of many fundamental concepts & iOS Development as a whole.
I mean many of us might not have the answers to the above questions. But, most of us might know Link Binary with Libraries & Frameworks, Libraries and Embedded Content Xcode Settings which are like the core concepts behind most of the things.
As time flows & the project grows many of us would land in a place where we have to rethink the project setup. I think that won’t be as easy as advertised by
pod deintegrate because it’s not just about building a new setup in a couple of weeks, it’s also about adopting a new development habit altogether.
Few common such situations can be:
Imagine you are working in a submodules setup. Every submodule (a framework) will have its own
podspec. Let’s say each has 5 dependencies, total App dependencies will be 25.
Trust me, I have seen up to 60 dependencies in Apps.
Sooner or later you would hit a threshold on Build Times (even incremental builds) or Launch Times.
I have seen clean build times up to 5 mins & incremental build times up to 2 mins. I have also seen Launch Times up to 10 sec in slower devices (App Store would reject if it’s > 4 sec, Apple suggests keeping it around 400 ms).
The reason for both the problems is too many dynamic Libraries (Apple suggests keeping it around 6). The solution will be around converting dynamic libraries into static or combining multiple dynamic frameworks into fewer dynamic frameworks. I have seen really good engineers struggle for weeks to get it right, not because it’s difficult, but because it’s too tedious or monotonous on an insanely big project.
There are times when things don’t go well with
podfile at least as per expectations, and we end up choosing something that works as shown below.
Two different podfile setup
When we are doing such tradeoffs, we often forget to ask the right questions, instead tend to convince/believe that maybe we were doing something wrong. But as a matter of fact, there is a change of approach as per convenience, internally by cocoapods which makes it work at the end.
Something similar happens when we are using
Development Pods &
Subspecs, the expectation is it should bring in all the development dependencies to the App Target. But, sometimes it doesn’t, out of confusion we add the dependencies explicitly and it works. And sometimes it works without doing anything which leaves you surprised. Again, we don’t ask the right questions when something works.
There are times when we do weird things like commenting some
frameworks.sh just to make the compiler happy and try to explain the solution instead of understanding the problem.
I believe our App cycle gets trapped in the timelines of dependencies when we go with cocoapods.
Imagine there is a new swift/OS release and you are excited to bring in some cool features to your app from those new releases. But, you have to wait for the framework authors to do the same.
Suppose you are trying to reduce Build Times and you decide to use pre-built binaries, you have to wait/ask framework authors to do the same.
This gets really difficult with not so popular/maintained third party dependency which you used back in time. Now, you can’t go back in time & remove them as it might break the behavior users are expecting or it would burn some midnight oil. Basically, you are trapped in a causal loop️.
This section is completely based on my opinion.
At first look, Cocoapods feels like a shiny solution for managing dependencies,
clean build &
pod install seems like a silver bullet in a candy wrapper.
But, I feel that’s not true in a long run. It comes with a lack of control & clarity. Carthage does a better job when it comes to giving control back to developers, but it’s not great with static libraries & submodules. Also, there is a new kid on the block, SPM. All of them come with some learning curve & shortcomings.
Realistically speaking we don’t update dependency versions very frequently. In my current organization it’s once in roughly 3 months, taking that into consideration I believe the old-school way of linking and embedding pre-built frameworks gives the control & most importantly the scope to understand how things really work. XCFramework by Apple is a great addition to exactly do that. Basically, update a dependency once & don’t worry about it or struggle with fixing errors till the next update, say 3 months.
That way, we can help Xcode with the dependency graph implicitly or explicitly which in turn will help us with faster incremental build times.
I would suggest not to depend on a Dependency Manager, rather Be the Dependency Manager 🙌
This article tries to highlight some of the problems with any Dependency Manager, not just Cocoapods. Most of them are out of my experiences & few are based on my opinions when compared to the other ways that can make developer's life easier.
Please use whatever suits you best, but take a logical decision considering your app’s use-case & most importantly try to understand how they all work behind the hood.
In the next article, I will try to put together how you can get rid of Dependency Manager with little effort & get the feel of all the advantages we talked about in this article. Stay Tuned.
This is a free third party commenting service we are using for you, which needs you to sign in to post a comment, but the good bit is you can stay anonymous while commenting.