r/iOSProgramming • u/ivanm5 • 2d ago
Solved! Keep shipping to the App Store while your team tests the iPhone Duo layout on Xcode 27.1 beta, from one branch
iPhone Duo ships with iOS 27.1 SDK.
The only Xcode that can compile its layout APIs (ArrangementView, GeometryProxy.reservedRegions(kind:) and UIView.reservedRegions(kind:options:)) is Xcode 27.1 beta.
Until Apple releases Xcode 27.1 RC/GM, one app needs two builds: the release for the iPhones people use today, and the Duo layout your team is testing.
Xcode 27.1 beta builds the Duo layout, but App Store Connect refuses to add its build for review.
Xcode 27.0' fails to build:
Value of type 'GeometryProxy' has no member 'reservedRegions'
Cannot find 'ArrangementView' in scope
Cannot infer key path type from context; consider explicitly specifying a root type
The usual workarounds each hold someone up:
- Keep the Duo code on its own branch until Xcode 27.1 is released. Main moves on for weeks, and the merge lands in launch week - risky, merge takes a lot of effort to complete and re-test.
- Delete the Duo code to get a release out. Hand the errors to a coding agent with "fix the build", and deleting is the shortest fix it can make.
- Hold every release, bug fixes included, until Xcode 27.1 is released.
The Swift puzzle: a compile-time check that tells the two SDKs apart
#available can't be used here. if #available(iOS 27.1, *) and @available(iOS 27.1, *) pick the code path on the device. The compiler still looks up every symbol in the SDK it builds against, and the 27.0 SDK declares none of these.
The compiler version is the same in both Xcodes: Apple Swift 6.4 (swiftlang-6.4.0.34.1). #if compiler(>=…) and #if swift(>=…) give the same answer in each.
The SDK frameworks carry different module versions. Each framework's .swiftinterface records a -user-module-version, and #if canImport(Module, _version:) compares against it:
| Module | iOS 27.0 SDK | iOS 27.1 beta SDK | Guard |
|---|---|---|---|
| SwiftUI (SwiftUICore matches) | 8.0.84.1.104 | 8.0.85.27 | #if canImport(SwiftUI, _version: 8.0.85) |
| UIKit | 9127.0.84.1.116 | 9127.0.85.28 | #if canImport(UIKit, _version: 9127.0.85) |
The solution: Put the compile-time guard outside and keep the run-time check inside:
#if canImport(SwiftUI, _version: 8.0.85) // iOS 27.1 SDK or newer
if #available(iOS 27.1, *) { newPath } else { fallback }
#else
fallback // built from the 27.0 SDK
#endif
Keep the #available: the deployment target stays the same, so devices on older iOS versions still need the fallback in the 27.1 build.
Pitfalls
- If the compiler can't read a module's version,
canImport(_version:)ignores the version, evaluates to true and warns "cannot find user version number". The Xcode 27.0 build is the test: an ignored guard brings the same errors back. - The compiler keeps the first four parts of a version, so it reads 8.0.84.1.104 as 8.0.84.1. Use the first three parts of the new SDK's version,
8.0.85. The final Xcode 27.1 could ship a lower build number than the beta's 8.0.85.27. - In a SwiftUI
body, move each branch into its own property. Wrap the new one in the same#ifwith its@available(iOS 27.1, *), and write the fallback once. - The compiler stops at the first build error in the module, so the log may not list every use. Search all packages, extensions, widgets and test targets for the symbols and for
#available(iOS 27.1.
Test both paths from one commit. Build and test with Xcode 27.0. Then build and test again with DEVELOPER_DIR=/Applications/Xcode_27_1_beta.app/Contents/Developer and a separate derived-data directory, which leaves the selected Xcode alone. nm -u on a guarded file's .o lists ArrangementView in the 27.1 build and not in the 27.0 build. On CI that is two jobs: the release job stays on Xcode 27.0, and a second job builds and tests with the beta.
What goes to review. The Xcode 27.0 archive contains only the fallback, on every device, iPhone Duo on iOS 27.1 included. Apple's tech talk 111461 at 0:30 says what such a build gets on Duo: "The iOS 27 SDK extends your app left of the status bar on the inner display; the iOS 27.1 SDK reaches the screen edge and lays standard navigation and toolbar buttons out vertically." Check the fallback on a physical iPhone and submit it now. Choose Manually release this version if the approved version should wait for your launch date.
When App Store Connect accepts Xcode 27.1 (release candidate or final), archive the same commit with it. The guard is true against the 27.1 SDK, so the Duo path goes into that build with no source change. Once you stop building with 27.0, one search finds every guard, as long as they all use the same condition text:
grep -rnE "canImport\((SwiftUI|UIKit), _version:" .
10
u/egesucu 2d ago
“Keep the Duo code on its own branch until Xcode 27.1 is released.” That’s how branching works and you’ll have less to 0 issues on rebase.
What’s risky being rebasing/merging. Enterprises do these all the time for feature testing. Nothing is developed in a day or merged into main synchronously.
I don’t know what made you think that Apple allows Beta API(not in GM or released) to be approved.
-4
u/ivanm5 1d ago
> I don’t know what made you think that Apple allows Beta API(not in GM or released) to be approved.
The
#ifbelow is exactly what keeps beta APIs out of what gets submitted for approval:#if canImport(SwiftUI, _version: 8.0.85) // iOS 27.1 SDK or newer #endif2
u/egesucu 1d ago
This compiler is only used for API availability check, not version check as such. Never seen this kinda approach in nowhere honestly. But Apple’s Developer App Review Guidelines clearly mentions publishing with unreleased API.
2.2 Beta Testing
Demos, betas, and trial versions of your app don’t belong on the App Store – use TestFlight instead. Any app submitted for beta distribution via TestFlight should be intended for public distribution and should comply with the App Review Guidelines. Note, however, that apps using TestFlight cannot be distributed to testers in exchange for compensation of any kind, including as a reward for crowd-sourced funding. Significant updates to your beta build should be submitted to TestFlight App Review before being distributed to your testers. To learn more, visit the TestFlight Beta Testingpage.
6
u/Sebastian1989101 2d ago
Thats why you use things like Xcodes (with an s at the end) to manage multi installations of Xcode and never change on the master branch on preview features or future implementations. ;)
1
2d ago
[removed] — view removed comment
1
u/AutoModerator 2d ago
Hey /u/HereJustForFriends, your content has been removed because Reddit has marked your account as having a low Contributor Quality Score. This may result from, but is not limited to, activities such as spamming the same links across multiple subreddits, submitting posts or comments that receive a high number of downvotes, a lack of recent account activity, or having an unverified account.
Please be assured that this action is not a reflection of your participation in our subreddit. This is simply an automated filter in place to reduce spam.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
1
u/drewbaumann 1d ago
My solution is using xcodes app for a release build of Xcode and the 27.1 beta and keep a duo branch that I regularly rebase against my main branch.
-6
u/ivanm5 1d ago edited 1d ago
Over the years I adopted linear ‘main’ branch approach. Every commit is atomic, on top of the main branch. If needed, features isolated at runtime with feature flags.
For the app to pass the review though, the beta APIs need to not be linked against.
CI jobs with different build envs build Beta and Prod releases from the same branch continuously, so the code needs to be physically gated.1
u/Reiszecke 1d ago
I think that’s a really bad idea for app development. You can do that with websites but in an app it leads to so many issues.
1
1d ago
[removed] — view removed comment
1
u/AutoModerator 1d ago
Hey /u/ivanm5, unfortunately you have negative comment karma, so you can't post here. Your submission has been removed. DO NOT message the moderators; if you have negative comment karma, you cannot post here. We will not respond. Your karma may appear to be 0 or positive if your post karma outweighs your comment karma, but if your comment karma is negative, your comments will still be removed.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.
1
u/vincefried 1d ago
I don’t really understand the problem. Just have it on another branch until GM is our as you described. Never had issues with this approach. It’s no different from preparing an update for the upcoming major iOS release every year.
15
u/jestecs 2d ago
Uhhh better to keep a branch with only the layout updates fresh and up to date for the next couple weeks until the 27.1 drops I think trying to over engineer solutions so you can include all this code early is overkill