Just fucking use UIKit

Recommended by 9 out of 10 developers who tried SwiftUI.

Every year at WWDC, someone stands on stage and shows you a list inside a navigation stack with a gradient and a spinning emoji, and the crowd loses their minds. “SwiftUI is the future!” they say, furiously rewriting their production app for the fourth time because NavigationView got deprecated and replaced by NavigationStack which will probably get replaced by NavigationHopeThisOneWorks next June.

Meanwhile, UIKit has been shipping apps since 2008. Your bank app? UIKit. Instagram? UIKit. That app with 200 million users that hasn’t crashed in three years? Take a wild guess.

Oh, and not even Apple is deprecating UIKit. They keep adding new APIs to it every year: updateProperties(), UIUpdateLink, symbol animations, trait system overhauls. If Apple thought UIKit was dead, they’d stop investing in it. They haven’t.

@State of confusion.

SwiftUI has @State, @Binding, @StateObject, @ObservedObject, @EnvironmentObject, @Environment, @Observable, @Bindable, and @AppStorage. That’s nine ways to hold a string. Nine. UIKit has properties. You set them. They stay set. Revolutionary.

In SwiftUI, you need a PhD in property wrapper semantics to understand why your view rebuilt 67 times when you changed a boolean. In UIKit, you change the boolean. Then you update the label. Cause and effect. Remember that?

Push it. Pop it. Ship it.

UIKit’s UINavigationController has worked reliably since iOS 2. You know exactly what’s on the stack because you put it there.

SwiftUI’s navigation has been rewritten three times and still can’t do a reliable deep link without sacrificing a view model to the NavigationPath gods. Want to pop to root? Good luck. Want to pop two screens back? Write a blog post about it, because you’ve entered uncharted territory.

Worse, SwiftUI welds your navigation logic directly into your view hierarchy. Every navigationDestination lives inside a view body. Every route is a modifier. Your screens can’t exist without knowing where they came from and where they’re going. In UIKit, a coordinator or router handles all of that. Your view controllers don’t know or care who pushed them. That’s called separation of concerns. SwiftUI says “I don’t know her.”

The compiler can type-check this in reasonable time.

Set a breakpoint in viewDidLoad. It hits once. You see your view controller. You see its properties. You can po anything. You can even open the view debugger and it makes sense.

Now try debugging a SwiftUI view body. Your breakpoint hits fourteen times. Self._printChanges() tells you something changed but won’t tell you what or why. The view debugger shows a tree of ModifiedContent<ModifiedContent<ModifiedContent<...>>> nested so deep it looks like it’s trying to reach the center of the Earth.

Scroll like you mean it.

UICollectionView with diffable data sources handles 100,000 items without breaking a sweat. Cell prefetching, self-sizing cells, compositional layouts. All battle-tested in production across billions (with a B) of devices.

SwiftUI’s List can’t match that. And LazyVGrid is lazy the way a goldfish is forgetful. It loads views on demand, sure. It just never learned to reuse them.

“I have this thing where I get older but just never wiser.” — Taylor Swift, after trying to get a List to scroll smoothly for the 13th time.

The reviews are in.

“SwiftUI is nearly at parity.”
Iceberg meme: UIScrollView has 15+ delegate methods and properties below the surface, SwiftUI ScrollView has two
Jacob Bartlett — iOS at Granola, author of Jacob’s Tech Tavern
X, Apr 2026
“I spent a year integrating SwiftUI into my apps, discovering my mistake at great cost, and years-since unwinding it right back out of them. I have no confidence in it ever being the only way to make quality apps. Zero.”
Steve Troughton-Smith — Indie developer
Mastodon, Dec 2025
“SwiftUI will be six years old this June. Is it likely to survive another couple of decades, or do we need another reboot and new approach to UI?”
Marc Edwards — Founder of Bjango
Mastodon, Jan 2025
“I should never need to tell my customers, ‘That was too difficult to achieve in SwiftUI, so that feature is gone.’”
Marco Arment — Creator of Overcast
Mastodon, Feb 2024

If SwiftUI is the future, the future is behind schedule.

“Apple said SwiftUI is the best way to build apps.”

Apple also said the butterfly keyboard was “four times more stable.” It broke when dust landed on it. Apple says a lot of things. Your users care about one thing: does the app work? Ship with whatever makes it work and won’t change next WWDC.

“But previews! Hot reload! Declarative syntax!”

Previews crash more often than they render. Hot reload works until it doesn’t, which is usually right before your demo. And “declarative” is a fancy word for “good luck figuring out which .onChange modifier is fighting which .task modifier.”

“But SwiftUI is so much easier and faster to build with!”

Easier to start, sure. Easier to finish? You save 20 minutes on a prototype and lose 20 hours when a sheet dismisses itself, a @State update triggers a full re-render, or an animation stutters because the framework diffed the entire view tree. SwiftUI is fast until it isn’t, and when it isn’t, you’re on your own, kid.

“UIKit is full of boilerplate!”

That mattered in 2020. Today, Claude and Copilot write your constraints and delegate methods in seconds. UIKit’s verbosity is a solved problem. SwiftUI’s unpredictability at runtime isn’t.

“UIKit is legacy code.”

UIKit has 18 years of documentation, Stack Overflow answers, and battle scars. Every LLM on the planet was trained on it. Ask any AI to write UI code and see which framework it nails on the first try. SwiftUI has 7 years of “filed a Radar.”

“But UIKit isn’t reactive!”

RxSwift called. It’s been reactive since 2015. Combine shipped with iOS 13. AsyncSequence works beautifully with UIKit. You’ve had reactive UIKit for a decade. You just didn’t need Apple to wrap it in a @Published for you.

“SwiftUI works great for simple apps.”

So does a spreadsheet. We’re not building simple apps. We’re building apps that people pay for, rely on, and use every single day. Those apps deserve a framework that doesn’t change its mind every September.

SwiftUI will be great someday. Maybe. But “someday” isn’t a shipping date. Your users don’t care what’s in your import statement. They care that the app launches fast, scrolls smooth, and doesn’t rebuild the entire screen when they tap a toggle.

UIKit gives you that today. It gave you that yesterday. It’ll give you that tomorrow, while SwiftUI is busy deprecating whatever they added last year.

Just fucking use UIKit.