SwiftUI After 7 Years: A Story of Mediocrity: Will it ever stop feeling like a beta? — Yakov Manshin

16 min read Original article ↗

Seven years after its blockbuster 2019 announcement, SwiftUI was supposed to be the mature, production-grade future of cross-platform UI development on all Apple platforms. Instead, SwiftUI feels like a perpetual beta, even in 2026. In this deep dive, I break down why the initial excitement has given way to deep professional frustration for senior engineers. I analyze the systemic issues with performance and layout predictability, the chaotic state of SwiftUI’s ever-changing data flow, and the frustrating lack of backward compatibility that forces developers into a nightmare of shims and workarounds.

Through real-world examples—including Apple’s own SwiftUI tutorial (which is broken) and a head-to-head performance comparison with UIKit (guess who wins)—I demonstrate how SwiftUI trades precise engineering for an illusion of convenience.

Beyond the code, this video explores a broader, more concerning shift in Cupertino: a transition away from the uncompromising craftsmanship of the original era of Cocoa, Aqua, and Auto Layout toward a modern corporate culture of “good enough” products. If you are tired of making excuses for broken features, fighting layout bugs, and doing Apple’s QA work for them, this perspective is for you.

Links

Video Transcript

Intro

Okay, let’s get on with it.

This is going to be a longer piece about SwiftUI, what’s wrong with it, and why I don’t believe it’s getting better any time soon. The past seven years haven’t turned SwiftUI into a real, production-grade UI framework: It still suffers from long-standing issues with layout consistency and performance.

But you don’t have to take my word for it; you can see for yourself in Apple’s official, first-party SwiftUI tutorial. Just download the complete demo project at the link below and run it on your Mac.

I’ll get back to this particular case later in this video. But let’s start with a short retrospective.

SwiftUI was announced back in 2019—and to much fanfare. I was there and witnessed it myself. Apple promised to end the era of fighting Auto Layout and rebuilding the app every time you make the tiniest of change.

Instead, you were going to get declarative syntax, the single source of truth, built-in animation, instant previews, and cross-platform reusability of your code. To me, it sounded too good to be true.

As it turned out, it was.

By this point, the initial excitement hasn’t just faded. It’s given way to a growing sense of deep professional frustration.

And after seven years, the excuse that “SwiftUI is still a young framework,” well, it’s just dead. In this industry, seven years is like an eternity. It’s roughly the time between this and this, and it’s more than the time between the first iPhone and the iOS 7 redesign. By comparison, SwiftUI feels like it’s in a perpetual beta state. Every new feature comes with a fine-print footnote. Every layout fix breaks two more things you didn’t even touch. And honestly? I’m tired of making excuses for all this in my own projects.

Why SwiftUI Exists

But before we have a look at SwiftUI’s specific strengths and weaknesses—mostly weaknesses—let’s see why SwiftUI even exists.

It’s not so much that Apple wanted to give you great dev tools, but because it sort of had to. Apple had to respond to the pressure from the competition. By the mid-2010s, Facebook’s React became de facto standard on the web, and soon React Native and Google’s Flutter started their conquest of mobile platforms. Both frameworks are reactive and declarative.

From the perspective of any business, building native apps started to look less and less appealing. Instead, they could use the same codebase on iOS and Android while also borrowing components from their own websites.

I believe there was one more reason, and it is the Mac App Store. When was the last time you opened it? And when was the last time you installed a new native app on your Mac? Yeah, same thing here.

The iOS App Store was the key step in Apple’s transition to services business, thanks to its 30% fee on every transaction. But on the Mac, many apps only worked in the browser, or as web apps in Electron wrappers.

SwiftUI was supposed to solve both of these problems: keep developers within the native ecosystem to build new apps, and make it easier to port existing ones to the Mac.

Reactive data flows, declarative layout, and cross-platform support were the key selling points of SwiftUI. Did Apple deliver on them? Let’s have a closer look.

Data Flow

One of the biggest pain points that continues to bother senior engineers, myself included, is the data flow. On paper, the single source of truth sounds like a dream. In practice, the reality is a confusing mess of property wrappers, macros, and ever-changing supporting frameworks.

We started with @State, @Binding, and ObservedObjects. Then Apple realized the performance was disastrous and SwiftUI was re-rendering views all the time. That’s when it introduced the Observation framework and the @Observable macro. They tried to solve the problem with compiler tricks, but it clearly wasn’t enough so the layout engine continued its guessing games.

In SwiftUI, you can never know for sure how many times a view will update and, when it does, why it chose to. Even using the undocumented debugging APIs doesn’t give you the full picture.

Data flow in SwiftUI is indeed reactive—but sometimes I wish it wasn’t, because it’s reactive in all the wrong ways. It often reacts to changes it should ignore, and it ignores the changes you actually care about. To me, SwiftUI’s reactivity is a black box: It makes achieving predictable behavior almost impossible.

Layout System

That brings us to the architectural side of things. Let’s talk about SwiftUI’s layout system. If you’ve spent any time building non-trivial interfaces, you know the frustration with SwiftUI. Its layout engine is incredibly unpredictable. It is built on the idea of size negotiation, and all this sounds logical in a keynote, but it feels like a nightmare when you try to build a floating view or a custom sidebar.

And speaking of custom sidebars. That demo project from the SwiftUI tutorial has a very standard, non-custom one. You build the project with the latest Xcode and launch the app on the latest macOS—only to get this. The first time I noticed it was over two years ago, and since then, nothing has changed.

Ah, sorry, one thing has changed. Thanks to Liquid Glass, the buttons now also have different sizes—though it’s hardly a SwiftUI problem.

What is a SwiftUI problem is the overall fragility of UI layouts. They fall apart in the most unexpected ways and at the most unfortunate moments. You can see it in the very real, production apps like UTM. It’s a fantastic piece of engineering, but its reliance on SwiftUI sometimes makes it feel like an early prototype.

In the end, you find yourself wrapping everything in a GeometryReader. And this is the ultimate admission of defeat. Once you use the GeometryReader, you’ve lost the declarative benefit entirely. Now you have to calculate coordinates manually, with even more verbosity than in Auto Layout (which is ironic). And the worst thing is that you might need to rewrite all your coordinate math in the very next update, just because SwiftUI’s layout system has changed again.

API Stability & Feature Parity

Moving on to API stability and feature parity—or the lack thereof. If you look at any modern SwiftUI codebase, you’ll find it full of those if #available checks, to the point where it’s almost comical—except it’s actually embarrassing. Someone was talking about writing less code and better code, back in 2019. And what do we have seven years in?

Let’s say you want to dismiss the keyboard on scroll, the same way it worked since iOS 7. Sorry, but you need iOS 16 to do this in SwiftUI.

Okay, maybe you want to let your users customize the window toolbar, just as they could since 2001 (or something like that). Well, SwiftUI received this “breakthrough” feature only a few years ago.

And then there’s the most basic task: displaying images you fetched from the network. Well, you better write your own fetcher, because AsyncImage was introduced only in iOS 15.

But if you want to also cache those images, I’ve got bad news for you: You can’t do it at all because right now, in July 2026, this API is still in beta.

For all these scenarios, developers usually come up with their own hacks and workarounds. And when Apple finally delivers the API that existed in AppKit or UIKit for decades, you have to maintain multiple implementations.

But even if the API you use was introduced in the very first version of SwiftUI, there’s a good change it’s been renamed or replaced with a similar one. One example is the NavigationView. It was known for being super buggy. And it seems that instead of fixing it, Apple decided to replace the entire component with the NavigationStack. But this, again, means that you have to keep separate branches, for newer and older versions.

So, is that “less code” or “better code?” You tell me because I kind of don’t know.

This constant API turnover results in development hell. Instead of declaring the UI structure once, we have to write shims and patches for compatibility, and then we have to hope that they wouldn’t break apart in the next update. We’re basically doing Apple’s QA work for them.

All these problems should’ve been solved in 2019—okay, maybe 2020. Yet even after seven years, SwiftUI hasn’t achieved feature parity with the “legacy” frameworks. SwiftUI is just running around in circles, and we have to run along just to stay in the same place.

But you know what? None of this would’ve been such a big problem—but only if Apple didn’t pretend that SwiftUI is rock-solid and built for ages. This wouldn’t have been a problem if you could just write code calling the latest APIs, and then back-deploy it to older versions of iOS. Yes, you’d still have to refactor and phase out old code more frequently. But at least the current version would work consistently on all devices.

It is the way modern UI works on Android: Jetpack Compose is just a package that you get and update through a dependency manager. Then it’s simply bundled with your executable and can be used on devices as old as 2014—all while delivering the exact same UI.

Performance

Let’s talk about performance. This is where you can’t fool anyone—even though Apple still tries by only showing SwiftUI running on the latest hardware. But the fact is, SwiftUI’s performance is just not up to the standard, no matter how many times Apple has promised to improve it. It is not what I expect from a “first-class framework” running on a “premium platform.”

For example, here’s my own head-to-head comparison of UIKit and SwiftUI. The test is a simple image gallery used in the previous version of my playground app.

Why previous? Because I have since rebuilt the entire app using the ultimate cross-platform framework. But that’s a story for another time.

So, despite all the performance hacks, like decoding images on background threads, scrolling the SwiftUI grid consistently feels much less smooth. Needless to say, if you have to keep in mind some obscure optimization secrets just to make it work, all the initial simplicity of SwiftUI goes out the window.

It’s only one of the tests I performed, and I deliberately used an older iPhone for it. But it shouldn’t make any difference, because if you need an M5 Pro Max super chip just to show a bunch of JPEGs, there’s something seriously wrong with your entire architecture. That’s not how you build high-quality software; it just doesn’t work like that.

Cross-Platform Myth

This brings us to the final promise of SwiftUI—its cross-platform support. I watched a few old SwiftUI keynotes, and to be fair, I didn’t hear the words “write once, run anywhere” in any of them—it’s usually “learn those tools once, and then apply them everywhere.”

There’s but one problem. What you learned about SwiftUI on iOS is rarely applicable to layouts on the Mac. That is, unless you want to end up with UIs that feel alien, like those iPad apps that Apple brought to the Mac (yeah, these apps).

Yes, the core SwiftUI concepts, like data flow and compositional layout, are roughly the same. But the specific components you use, and the way you configure them, are often very different. Not to mention, the very same views can have inconsistent implementation across platforms.

In other words, UI design for a 6-inch phone and 27-inch desktop is not the same. Who would’ve thought?

In my experience, SwiftUI’s “learn once, apply anywhere” often turns into “learn once, learn twice, apply somewhere, debug everywhere.”

That is, of course, if you’re interested in building UIs that look native and professional. If not, SwiftUI can actually give you results that “will do” or results that are “good enough.”

Philosophical Shift

And actually, I view this “good enough” thing as the biggest problem here. I believe it serves as a sign of a major shift in Apple’s entire approach to software development. With SwiftUI, we’ve entered an era where something that “mostly works” is considered adequate. Or an era where covering only 90% of use cases is considered a success. The expectations of production-grade quality and stability gave way to so-called velocity—which is a word you use when you want to ship garbage, only do it faster.

In the days of Cocoa, that was unthinkable. In the early days of Mac OS X, that would’ve been a disaster. Can you imagine a SwiftUI version of that original Aqua keynote? Imagine for a second that instead of “liquid” buttons that look so good “you’d want to lick them,” Jobs presented flickering sidebars and jumping buttons. He would’ve been roasted.

But now, it seems that we’re settling for “good enough” products and “it will do” mentality. This is the standard of craftsmanship I’m not ready to accept.

And it’s not just a single framework issue. It’s a systemic shift. First, one company starts a trend on “moving fast and breaking things.” Gradually, more developers join it; not all of them move fast, but shipping broken things becomes normalized, even in first-party apps and system components.

For instance, Apple Music has for years had this bug where editing the queue would make the track list jump and then play an entirely wrong song.

TestFlight crops the selection with no padding.

The Settings app on the iPad shows crash reports like this, and even though I took this screenshot back in January, it hasn’t been fixed up until now.

The Home Screen shows duplicate icons for the same app. And it makes the status bar jump back and forth. And it shows outlines for icons that shouldn’t be displayed.

And even professional apps like Logic Pro now ship with missing localization. You know, those professional apps that are supposed to be the benchmark of quality and stability.

I can go on for a long time.

While not all of these examples use SwiftUI, they demonstrate the level of quality that Apple considers “acceptable” now. I didn’t have to dig deep to find them; these are the things that I personally saw in the past few months.

So with these examples in mind, it’s not surprising that the flagship system framework makes it nearly impossible to build an app that’s not broken in at least one way.

On Apple platforms in particular, this shift began around 2018, with those “alien” apps I already mentioned. It’s when Project Marzipan, later renamed Catalyst, first enabled UIKit code to be reused on the Mac. Tech reviewers tore apart the results, and here’s more screenshots.

But instead of doing the homework, Apple doubled-down on the idea of cross-platform development, with SwiftUI. And this brand-new, completely untested framework only introduced more issues with performance, stability, and visual appeal.

I conclude that lowering the bar for quality was a choice, not a necessity. I refuse to accept that choice. And that is why I can’t trust SwiftUI even after seven years.

Summary

As a bottom line, and to answer the question from the beginning, what is actually wrong with SwiftUI?

If you weigh in all the problems that haven’t been fixed in the seven years of its existence, the answer is,

Everything.

Or at least everything that’s important for building stable, performant, and maintainable systems.

The story of SwiftUI is a story of mediocrity and falling standards. We’re offered to trade predictable precision for an illusion of convenience. And then we’re forced to either spend the time debugging the framework, or ship broken apps as is.

As a senior engineer, I find neither of these options appealing. I don’t respect the “it will do” mindset, and I believe that users deserve better than “good enough.”

SwiftUI is not truly bad. It’s mediocre. And that, in my opinion, is much, much worse.

So for now, I still prefer the “legacy” UI frameworks.

Afterthought

The idea of this piece came to me even before I started this channel. For years, I’ve been observing SwiftUI’s struggle to become a solid replacement for AppKit and UIKit—in other words, to become what Apple promised it to be, all the way back in 2019.

For years, I’ve been testing SwiftUI’s new iterations in the hopes that the problems that plague it will finally get fixed.

But as the time goes by, SwiftUI’s not becoming better in a fundamental way. It’s just as half-baked as it was seven years ago, and apps built with SwiftUI mostly turn out just as unremarkable.

But SwiftUI’s struggle is not the only thing I’ve been observing. I’ve also been observing software engineers who sincerely believed that if a feature built with SwiftUI works right here and right now, then their job is done. Unless they choose the inferior tools on purpose, I don’t really blame them.

Well, maybe a little, because you can’t ignore the long-term cost of maintenance without paying the price.

Anyway, individual engineers aren’t usually the ones who pay it; their employers are. But in the times when businesses are obsessed with replacing humans with AI agents, it’s hard to expect the quality of their products to improve. And because these are also the same businesses that view software development as a commodity or linear production, they typically want to ship “fast” instead of “right.” We can already see the results of this approach, and we’re going to see more in the future.

Outro

That’s it for today’s Code Bird video, but I am very interested in your opinion, especially if you disagree with me. I would love to read your comments down below.

Give this video a thumbs-up if you feel it deserves one. Subscribe to the channel for more engineering content.

I’ll see you in the next video. Until then, make your tools fly.