Francisco José García Navarro
Published:WWDC 2026 for teams in production: Swift 6.3, SwiftUI and what breaks in iOS 27
" AI has eaten the headlines. But if you maintain a large app in production, the real work this cycle is in Swift 6.3/6.4, in the new SwiftUI and in the breaking platform changes. This is what I would be planning before September. "
This article closes my series on WWDC 2026. I have already written about AI on iOS: agentic Xcode and Foundation Models and about why iOS 27's accessibility features don't make you EAA-compliant. If that's what you're after, it's there.
This article is about everything else. About what doesn't make the headlines but determines how much the iOS 27 cycle is going to hurt: the breaking platform changes, what Swift 6.3 and 6.4 bring, and a SwiftUI that this year has gone for the foundations rather than the fireworks.
After 11 years building native iOS in banking, retail and insurance apps, I have a rule: the "boring" WWDC cycles are the ones that generate the most work. This is one of them.
What breaks: the changes you cannot postpone
1. The UIScene life cycle becomes mandatory. Confirmed without ambiguity in the "Modernize your UIKit app" session: when compiling with the iOS 27 SDK, the UIApplicationDelegate-based life cycle stops being an option — without a UISceneDelegate, your app simply won't launch. If you've spent years putting off the scene migration — and I've seen plenty of apps putting it off — this is the moment it stops being technical debt and becomes a blocker.
2. Your iPhone app becomes fully resizable. In iOS 27, an iPhone app running on iPad resizes like any iPad app, and in iPhone Mirroring the window stretches freely on the Mac. The fixed-size compatibility mode is gone. And two conceptual demolitions come with it: the idiom no longer works for layout decisions (an iPhone app on iPad still reports the phone idiom, yet it's resizable) and neither does interface orientation — in resizable environments, your supported orientations become a preference the system may ignore. What remains standing: size classes, the actual size of your view and the effective geometry of the window scene. No UIScreen.main. For games, UIRequiresFullscreen is still honoured on iPhone, but its meaning changes: it no longer opts you out of resizing — it turns it into discrete resizing across screen configurations. Xcode 27 ships the Device Hub and Previews with live resizing precisely to test all of this.
3. In device management, declarative is now the standard. Apple's message in the device management session is explicit: declarative management "is no longer the future, it's the standard", with credential configuration profiles transitioning to declarative configurations. If you distribute to corporate fleets with an MDM anchored in the classic command model, the direction is unequivocal, and it's worth talking to your IT team this summer — not when your MDM vendor forces the change on you.
Of the three, the one teams underestimate most is the second. Resizable doesn't mean "it doesn't crash when the size changes": it means your layouts, your image caches, your custom cells and your assumptions about UIScreen withstand variable geometry. In an app with years of history, that's an audit, not a ticket. Apple knows it, which is why Xcode 27 includes an app modernization skill for agents that automatically converts UIScreen.main calls, orientation checks and even the scene life cycle migration — I covered what it means to delegate that work to an agent (and audit what it produces) in the AI article of this series.
Swift 6.3 and 6.4: less friction, more control
First things first: if your strict concurrency migration stalled in 2024 or 2025, Swift 6.3/6.4 won't do it for you — but it does remove several of the specific stones that teams I've seen migrate kept tripping over. The big model change (MainActor by default, "Approachable Concurrency") arrived with Swift 6.2; this year is about sanding down friction.
Concurrency: the small stones that stalled migrations
weak let. The classic: a class that needed@unchecked Sendablejust because it had aweak var. Now thatweakcan be alet, immutable, and Sendable checking passes cleanly. It's a one-line change that removes an@unchecked— and every@uncheckedyou remove is one less promise you have to keep by hand.- Explicit
~Sendable. You can declare that a type is not Sendable, and without blocking its subclasses from being Sendable themselves. In inherited UIKit hierarchies, this documents intent in the right place: the code. - Warning for silenced errors in Tasks. If you launch a
Taskwhose error nobody collects, the compiler now warns you. In production code I have audited far too manyTask { try await ... }where the error died in silence. This warning alone justifies updating. asyncindefer. The restriction on calling async functions from adeferblock disappears. Asynchronous resource clean-up without contortions.
@diagnose: surgical control over warnings
This is the one that interests me most for enterprise work. @diagnose lets you change the behaviour of groups of warnings on a specific declaration:
@diagnose(.ignore, .deprecatedDeclaration)
func legacyBridge() {
// deprecated API we can't replace yet:
// silenced here, and only here
}
@diagnose(.error, .strictMemorySafety)
func verifySignature(_ data: Span<UInt8>) {
// in security-critical code, what was a warning is now an error
}
In a module-by-module migration, this changes the conversation with the team: instead of a sea of warnings everyone learns to ignore (and with them, the warnings that do matter), you confine the noise to the points where the debt is deliberate and escalate to error what you don't want slipping through. In banking apps, being able to enforce strict memory safety as an error in cryptography and signing functions is exactly the kind of tool I want.
Module selectors: :: to disambiguate modules
Swift 6.3 introduces syntax for the classic conflict in modularised apps: two modules with types of the same name.
import SwiftUI
import MyDatabase // also defines a View type
let view: SwiftUI::View // "::" forces SwiftUI to be interpreted as a module
If you work on a 100+ module app, you know this isn't a laboratory case: it happens, and until now it was solved with defensive typealiases or awkward renames. Note Apple's own advice, which I subscribe to: it's a tool for resolving conflicts you don't control, not a licence to design APIs with duplicate names.
Swift Testing: migrating from XCTest is no longer scary
For enterprise teams with large suites, this year's news matters: XCTest assertion failures are now reported as issues when called from Swift Testing, and vice versa — #expect works inside an XCTestCase. Translation: you can migrate your suite in parts, keep your helpers built on XCTest, and lose no coverage along the way. On top of that come configurable severity in Issue.record (issues that warn without breaking CI), Test.cancel for dynamically cancelling arguments of parameterised tests, and swift test with configurable retries to hunt flaky tests by re-running only the ones that fail.
If you've spent a year saying "we'll migrate to Swift Testing when it's safe": it's safe now.
Performance: ownership without unsafe pointers
Swift 6.3/6.4 keeps building out the ownership system, and for the first time I find it complete enough for performance-sensitive production code:
borrowandmutateaccessors: access to shared storage without copying. The canonical example: a struct with a 2 KBInlineArrayinside — withget/setyou copy the 2 KB to touch an Int; withborrow/mutate, you mutate in place.@inline(always)and@specialized: explicit control over inlining and generic specialisation when the optimiser doesn't get it right on its own.Ref/MutableRef: keeping an access "open" (for instance, a dictionary lookup inside a loop) safely, without theinoutparameter trick.- The
Iterableprotocol:forloops that borrow elements instead of copying them, with no reference counting per iteration.
Do you need this in your ViewModel? No. Do you need it in an encryption framework, a real-time market data parser or an image pipeline? That's where you used to end up with UnsafePointer — and now you don't.
And a strategic note: official Swift on Android
Swift 6.3 includes the first official Swift SDK for Android, with improved Java/Kotlin interoperability. It changes nothing today for an iOS app in production, but it does change a conversation I often have with CTOs: the "we need to share logic across platforms" one. Until now the pragmatic answer was KMP for the domain layer; from now on, sharing Swift is an option that deserves serious evaluation. I'll leave it noted — it's worth an article of its own.
SwiftUI: the year of the foundations
The striking thing about SwiftUI this year isn't any spectacular API. It's that almost everything important improves without touching code — and the two or three things you do touch go straight at enterprise pain points.
Liquid Glass v2, for free. You recompile with the new SDK and the app adopts the refined look: consistent corners on macOS, response to the system tint slider, dimming of inactive windows on iPad. Zero lines.
Toolbars designed for resizing. With apps now resizable, the system hides toolbar items when they don't fit. The new APIs give you the control that was missing: visibilityPriority(.high) so Undo/Redo don't disappear, ToolbarOverflowMenu to group the secondary items, pinned placements for what should never be hidden, and toolbarMinimizeBehavior(.onScrollDown) to reclaim vertical space. If you have a productivity app, this is the first API I would touch.
@State is now a macro — and it's lazy. The quiet change with the biggest performance impact: @Observable classes stored in @State are initialised once, not on every view reinitialisation. Until now, every re-init of the parent created a new instance of your store... which was thrown away immediately. If your stores do work in their init (and they shouldn't, but the real world is the real world), this removes wasted work on every update. A warning: it's the conversion of State from Dynamic Property to macro, and it can break code — if you assign a default value and also assign in the init, you'll get a "use before initialization" error. The fix is removing the redundant default. And it has been back-deployed to iOS 17.
Faster type-checking with ContentBuilder. The most common builders (Section, Group, ForEach...) are unified under a single ContentBuilder, eliminating the combinatorial explosion of overloads behind the famous "unable to type-check this expression in reasonable time". It works with any deployment target when compiling with Xcode 27. In large SwiftUI codebases, this is real compile time you get back.
AsyncImage finally caches. Standard HTTP caching by default, respecting server headers, with no code changes. And if you need control, you can pass your own URLRequest or a URLSession with whatever URLCache you like. The number of home-made AsyncImage wrappers I've seen in audits just to get caching... retire them.
Observation Tracking in UIKit and AppKit, on by default. For apps that still live mostly in UIKit — which is most enterprise apps — this is the most useful change of the year: UIKit/AppKit views now automatically observe properties of @Observable types inside draw, layout, updateConstraints and friends. No more manual setNeedsDisplay() to keep views in sync with the model. On by default in the 2026 releases, and back-deployable to iOS 18 / macOS 15 with an Info.plist key. The strategic play: migrate your model to @Observable before touching a single view — your existing UIViews benefit already, and when you rewrite a component in SwiftUI, the model will be ready. It's the Strangler Fig pattern applied to the data layer.
Reordering and swipe actions in any container. The new reorderable + reorderContainer API gives you drag-to-reorder in List, LazyVGrid or any container with the same code, and swipe actions stop being exclusive to List. Fewer reasons to fall back to UICollectionView for one interaction.
And for document apps, there's a complete new API (ReadableDocument/WritableDocument) with asynchronous reading/writing off the main actor and incremental writing by comparing snapshots. Niche, but if it's your niche, it's the rework you've been asking for for years.
What I would do before September
If I'm in charge of technical planning for a large app, my order is this:
- Audit the three breaking changes. Are we on UIScene? Do we withstand resizing? Do we depend on classic MDM? Every "no" is an epic, not a ticket.
- Compile with the Xcode 27 beta now, even if you won't ship with it. The cost of discovering in August what you could have known in July is paid in September.
- Test the app in the resizable simulator. It's the cheapest way to uncover broken geometry assumptions.
- Resume the concurrency migration if it's stalled, using
@diagnoseto confine the noise andweak let/~Sendableto clean up the accumulated@unchecked Sendable. - Plan the migration to Swift Testing module by module, now that interoperability with XCTest guarantees no loss of coverage.
- Check for the
@Statemacro compile error as soon as you build with the new SDK: it's mechanical to fix, but you have to go through it.
WWDC 2026 is a roll-up-your-sleeves cycle: little pyrotechnics and plenty of plumbing. But plumbing done well is what separates an app that ages with dignity from one that fills up with patches. And unlike AI — where there's still room to wait and see — here the deadlines are set by the SDK.
Frequently asked questions
Which iOS 27 changes can break an existing app?
Three: the UIScene life cycle becomes mandatory when compiling with the iOS 27 SDK (without a UISceneDelegate the app won't launch), iPhone apps become fully resizable on iPad and in iPhone Mirroring, and declarative device management becomes the standard over the classic MDM command model.
Does Swift 6.3 make the strict concurrency migration easier?
It won't do it for you, but it removes specific friction: weak let lets you clean up many @unchecked Sendable annotations, ~Sendable documents non-Sendable types explicitly, and the compiler warns about silenced errors in Tasks. The big model change arrived with Swift 6.2; 6.3/6.4 sand down the stones that stalled migrations.
Is it safe to migrate from XCTest to Swift Testing in 2026?
Yes. From this cycle, XCTest assertion failures are reported as issues when called from Swift Testing and vice versa, which lets you migrate the suite module by module while keeping your existing helpers, with no loss of coverage.
Which SwiftUI improvements arrive without code changes?
Liquid Glass v2 when recompiling with the new SDK, HTTP caching by default in AsyncImage, faster type-checking with ContentBuilder, and automatic Observation Tracking in UIKit/AppKit (on by default in the 2026 releases).
Sources (WWDC 2026 sessions)
Is your team facing iOS 27 SDK adoption, the strict concurrency migration or a UIKit app that needs modernising without stopping the roadmap? That's exactly the kind of work I do as a senior iOS contractor embedded in teams.
About the author
Francisco José García Navarro is the co-founder and Senior iOS Architect at AtalayaSoft, with over 25 years in software development and 11+ in native iOS. Throughout his career he has worked with high-profile clients such as Zara (Inditex), Banco Santander, AXA, El País, National Geographic, Fox International Channels, and the Thyssen-Bornemisza Museum.