Modern iOS Performance Myths: Episode 1


Greetings, traveler!

I recently joined Swift Academy for a podcast episode about iOS performance. The episode is called “Modern iOS Performance Myths”, hosted by Walid Sassi, and I had a great discussion there together with Bogdan Poplauschi.

The conversation became bigger than we expected, so we split it into two episodes.

What we discussed in the first episode

The first episode is mostly about how iOS engineers should think about performance in 2026.

We started with a simple question that is not that simple in practice: what does a “performant” iOS app actually mean today? It is easy to reduce performance to speed, launch time, or FPS. But users do not experience metrics directly. They experience waiting, blocked interactions, delayed feedback, broken animations, and screens that technically load fast but still feel uncomfortable.

That led us to perceived performance. Why can an app be technically fast but still feel slow? Sometimes the problem is not the network request or the algorithm. Sometimes the app gives feedback too late, updates the UI in a confusing order, or blocks the main thread for a short moment at exactly the wrong time.

We also spent a lot of time on SwiftUI.

SwiftUI has made many things easier, but it has not made performance free. Some costs are now less visible. Body evaluation, diffing, layout, identity, environment propagation, and state invalidation can become difficult to reason about when the app grows.

One of the questions I liked most was whether Environment is becoming the new Service Locator. It is convenient. Maybe too convenient. When too many dependencies and global objects move into Environment, the architecture can start to look clean from the outside while becoming harder to trace and test.

We also talked about SwiftUI patterns that become risky at scale: large observable models, unstable identity, broad invalidation, heavy view trees, AnyView abuse, and state that changes more often than the UI really needs.

Another part of the conversation was about rendering. What actually consumes the frame budget? It is rarely one dramatic thing. More often it is a mix of layout, text measurement, image decoding, view updates, Core Animation commits, GPU work, blending, and small pieces of main-thread work that stack together.

Of course, we also touched UIKit. Is UIKit deprecated? Definitely not. SwiftUI is the direction for many new interfaces, but UIKit is still everywhere, still powerful, and still necessary in many production apps. The interesting question is where each framework gives the team better control.

Toward the end, we discussed debugging. Instruments is essential, but experienced engineers often have to go beyond the first obvious trace. Some issues are hidden in state updates, view identity, scheduling, task boundaries, or code that looks harmless in isolation. Performance investigation is often detective work.

And finally, we talked about concurrency and parallelism. Many developers still mix them up. Swift Concurrency gives us better tools for expressing asynchronous work, but it does not automatically make code parallel, faster, or cheaper. Used poorly, it can just move the bottleneck somewhere else.