Getting Swift 3 compatibility in a large Objective-C codebase

Standard Bank Engineering
Standard Bank Engineering
6 min readMay 8, 2017

Airbnb recently posted about their experience migrating from Swift 2 to Swift 3. We here at Standard Bank, quite recently, took the plunge and made our codebase (roughly 500 000 lines of code) Swift 3 compatible. This article works to highlight some of the difficulties we faced, some we continue to face, and how we’re in a position to move forward by writing new code in Swift while still reusing existing code written in Objective-C.

What triggered the drive?

We decided to integrate Swift into our codebase for the following reasons:

  • Objective-C is legacy and the longer we wait, the more legacy code we create and the bigger our Objective-C codebase will become.
  • It will become increasingly more difficult to find engineers who are not only proficient in writing Objective-C, but who are still willing to code in it.
  • Swift is safer, cleaner, easier to learn, and borrows some popular functional paradigms making it more enjoyable to write.
  • Teams that are still learning Swift and don’t feel comfortable writing full features in the new language can still write their code in Objective-C.

Setting business expectations

With Universal App being a priority from various stakeholders, we were able to introduce the Swift integration as a blocker for our next release. Having buy in from your stakeholders for these initiatives is a key success factor. In other words, we could not release a new iOS app unless the Swift conversion was done. However, a well-planned POC or Technical Spike was needed to estimate how long it would take to do the integration, and if in fact it could be done at all, before the block was introduced. This was successfully done on one of our repositories, then slowly rolled out to the various teams, with it being the teams’ responsibility to make their repository compatible.

Even with a successful POC, it is impossible to give an accurate timeline for how long the integration will actually take. So be prepared for a few bumps along the way. Persistence is key.

Even after a successful integration, it is realistic to expect some slow initial development. By understanding the advantages Swift has over Objective-C, planning how you intend to amend your architecture can eliminate a lot of headaches. Some things to think about:

Foundation for success

The foundation of our successful transition was built on three main pillars: a modular codebase, continuous integration and tests. We will explain why in the sections below.

Modular codebase

We have multiple cross-platform delivery teams. Each team oversees key areas of the banking experience while having the full stack of developers working to create their part of the application. We are able to achieve this modularity and team independence using Cocoapods.

Each team has their own ‘pod’ and can run independently of other teams. Each pod is then compiled into a framework in the main app. So when the conversion began, teams could still work and run their features even though the main app was broken.

Our modular architecture is also facilitated by a model hierarchy. Every team has their own module, which resides on tier 2. Tier 1 would be all our common code, including but not limited to our networking layer and base classes with common functionality.

Common code was simple enough to get into a framework, tell Cocoapods to compile as a framework, and convert all imports to modular versions of themselves. Once the Common framework built successfully, we could begin to start the conversion on Tier 2 modules and have teams start their part of the integration.

One of the major issues we faced with Cocoapods was transitive and circular dependencies. Unfortunately third-party libraries that were not Swift compatible had to go, and alternatives needed to be found. We ultimately fixed the circular dependencies by introducing another module that would hold the common interfaces used across frameworks.

Cocoapods proved to be instrumental during the process allowing our app to be modular as opposed to a monolith. If you’re looking at integrating Swift into a monolith codebase, you can refer to this video released recently as well.

Continuous Integration

Continuous Integration allows us to integrate code into a shared repository several times a day. Each check-in is then verified by an automated build, allowing teams to view when a build is broken and which team broke the build. So when the integration started, we were able to slowly watch all team builds turn from red to green as each team successfully integrated Swift into their repository.

Most importantly CI offers us and the bank a high-level status of the entire iOS team. This proved to be invaluable during the the integration process.

Test Driven Development

Test Driven Development is fundamental to our workflow at the bank, and indeed proved integral to our transition from Objective-C to Swift. This was an important factor as we had times when the app was running but the tests were failing. This demonstrated that there was functionality in the app that was not behaving as it should, and helped us quickly find and fix bugs within a reasonable timeframe. In essence it measured the integrity of the system after the integration took place. With the knowledge that the domain logic remained unaffected, we were able to run through a full regression test.

Moving forward

The biggest hurdle we face, now that we are using Swift in our Objective-C codebase, is interoperability. The favourable move is for teams to rewrite existing code into Swift, but time has proved an obstacle and not all teams have had the option. Our codebase is also too big to consider such a move.

Another path we have discovered is to completely avoid using any Swift code in Objective-C. Marking classes as @objc and having to inherit from NSObject is a necessary evil, but something we are working to stay away from. Even having to write a wrapper around some existing Objective-C code in Swift seems to be more favourable.

Conclusion

The transition of our code base from Objective C to Swift was fostered by an environment of flexibility and powered by the strong pool of resources we have at our disposal. This is evidenced by the fact that our code was Swift compatible in just one week.

This article has been purposefully broad, as its objective is to give an overview of our move from Objective C to Swift. In short, the three pillars we found integral to our transition were a modular codebase, a continuous integration system and rigorous testing of the codebase. Although we faced many obstacles along the way, ultimately the integration was a smooth one. We will look to follow up this article with some deep-dives into technical issues faced along the way, as well as ones we expect to experience in future. The full series will work toward one conclusion: upgrading your codebase to a Swift-compatible one is not only necessary, but entirely possible.

— -

We have an awesome team of people working here at Standard Bank. We get to solve complex problems at a large scale. We are always looking for talented and hardworking people. (Email us if you are interested in joining us.)

— -

Authors: Tyrone, Tesh, and PJ with the help of the entire iOS team who all made this possible.

--

--