I honestly thought I was getting somewhere with this, but alas, no. Every time I do anything in my List of ItemRows it jumps back to the top.
Here's the setup:
DataService.swift:
final class DataService {
static let shared = DataService()
private init() {}
let coreData: CoreData = CoreData()
let modelData: ModelData = ModelData()
}
ModelData.swift:
@Observable
class ModelData: ObservableObject {
var allItems: [ItemDetails]
var standardItems: [ItemDetails]
var archivedItems: [ItemDetails]
init() {
allItems = []
standardItems = []
archivedItems = []
}
func getInitialData() {
// Get all items, then split them into archived and non-archived sets, because you can't use `.filter` in a view...
allItems = dataService.coreData.getAllItems()
standardItems.append(contentsOf: allItems.filter { !$0.archived })
archivedItems.append(contentsOf: allItems.filter { $0.archived })
}
}
MainApp.swift:
// Get access to the data; this singleton is a global as non-view-based functions, including the `Scene`, need to access the model data
let dataService: DataService = DataService.shared
@main
struct MainApp: App {
// Should this be @ObservedObject or @StateObject?
@ObservedObject private var modelData: ModelData = dataService.modelData
// I would use @StateObject if the line was...
//@StateObject private var modelData: ModelData = ModelData() // right?
// But then I couldn't use modelData outside of the view hierarchy
var body: some Scene {
WindowGroup {
ZStack {
MainView()
.environment(modelData)
}
}
.onAppear {
modelData.getInitialData()
}
}
}
MainView.swift:
struct MainView: View {
@Environment(ModelData.self) private var modelData: ModelData
var body: some View {
...
ForEach(modelData.standardItems) { item in
ItemRow(item)
}
ForEach(modelData.archivedItems) { item in
ItemRow(item)
}
}
}
ItemRow.swift:
struct ItemRow: View {
@Environment(\.accessibilityDifferentiateWithoutColor) private var accessibilityDifferentiateWithoutColor
var item: ItemDetails
@State private var showDeleteConfirmation: Bool = false
var body: some View {
// Construct the row view
// `accessibilityDifferentiateWithoutColor` is used within the row to change colours if DWC is enabled, e.g. use different symbols instead of different colours for button images.
// Add the .leftSwipeButtons, .rightSwipeButtons, and .contextMenu
// Add the .confirmationDialog for when I want to ask for confirmation before deleting an item
}
}
Now, the problems:
Swipe an item row, tap one of the buttons, e.g. edit, and the list refreshes and jumps back to the top. In the console I see: ItemRow: @self, @identity, _accessibilityDifferentiateWithoutColor changed. Why did accessibilityDifferentiateWithoutColor change? The setting in Settings > Accessibility > Display & Text Size has not been changed, so why does the row's view think it changed?
With a .confirmationDialog attached to the end of the ItemRow (as seen in the code above), if I swipe and tap the delete button the list refreshes and jumps back to the top again. In the console I see: ItemRow: @self, @identity, _accessibilityDifferentiateWithoutColor, _showDeleteConfirmation changed. Right, it changed for the one row that I tapped the button for. Why does every row get redrawn?
I already had to shift from using the colorScheme environment variable to add new asset colours with light and dark variants to cover this, but you can't do that with DWC.
Honestly, managing state in SwiftUI is a nightmare. I had zero problems until iOS 26 started removing one or two rows when I scrolled, and the fix for that - using @Statebject/@ObservedObject - has introduced multiple further annoying, mind-bending problems, and necessitated massive daily refactorings. And, of course, plenty of my time islost trying to figure out where a problem is in the code because "The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions"...
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
We have encountered a problem on iOS 26. When switching to dark mode, the color of all subviews (font color, background color, etc.) of the Sidebar (Primary View) of UISplitViewController will not change. For example, if it is set to the color of UIColor.label, it will always be black and will not be white in dark mode.
On Xcode, just create a UISplitViewController in Storyboard without changing any settings, and run it directly to see the following:
The title of the Navigation Bar defaults to the label color, and it is still black after switching to dark mode.
There is no such problem in the Secondary View or other places.
This problem has occurred since iOS 26 beta 3, and iOS 26 beta 4 is now the same. But beta 1 and beta 2 have no problem.
I'm not sure if this is a bug, or if there is something that needs to be changed to adapt to iOS 26?
Hi, everyone
I have an app already in production that uses SwiftUI's lifecycle (paired with an AppDelegate). Due to some specific behaviour of the app, we decided to migrate the app to use UIKit's lifecycle, adding the corresponding SceneDelegate to the app, as well as modifying the Info.plist file accordingly to accommodate to these new changes.
Although everything seems to work when installing the app from zero, when installing it on top of another version, the screen goes black and the user cannot interact with the app at all unless they reinstall it completely. As I've read online, iOS is reusing the window configuration from the previous execution of the app. I know this because the AppDelegate's application(application:connectingSceneSession:options) is not being called when coming from a previous version of the app.
I would love to know what can I do to make this work because, as you may understand, we cannot ask our user base to reinstall the application.
Thank you very much.
The navigation title color is wrong (dark on dark background) when applying hard scrolledgeeffectstyle.
Illustrated by code example. In simulator or physical device.
Changing scrollEdgeEffectStyle to soft resolves the issue.
As does changing the listStyle.
@main
struct AppView: App {
var body: some Scene {
WindowGroup {
NavigationSplitView {
NavigationStack {
Section {
NavigationLink(destination: OptionsView()) {
Label("More Options", systemImage: "gearshape")
}
.isDetailLink(false)
} header: {
Text("WITH OPTIONS").bold()
}
.navigationTitle("TESTING")
}
} detail: {
Text("DETAIL")
}
.preferredColorScheme(.dark)
}
}
}
struct OptionsView: View {
var body: some View {
List {
Text("List Item")
}
.listStyle(.plain)
.navigationTitle("MORE OPTIONS TITLE")
.scrollEdgeEffectStyle(.hard, for: .all)
}
}
Submittted FB20811402
Bug appears in Landscape mode for iPhone only.
Any orientation for iPad.
Topic:
UI Frameworks
SubTopic:
SwiftUI
An WWDC 25 a neutral value was demonstrated that allows the Slider to be 'coloured in' from the point of the neutral value to the current thumb position. Trying to use this in Dev release 1 I get errors saying no such modifier.
Was this functionality released in Dev Release 1 or am I using it incorrectly?
hello im using the new IOS 26 api for passkey creation ASAuthorizationAccountCreationProvider
however it only seems to work with apple's Passwords app. Selecting 3rd party password apps (1Password, google chrome, etc) does not create the passkey.
The sign up sheet gives me the option to save in 3rd party apps, but when I select a 3rd party app, I just get the ASAuthorizationError cancelled error? So I dont even know what the problem is?
When selecting "Save in Passwords(apple's app)" during the sign up it works fine
Has anyone else run into this issue? Is there something I need to do enable 3rd party apps?
Generic parameter 'V' could not be inferred ERROR
I have a few view controllers in a large UIKit application that previously started showing content right below the bottom of the top navigation toolbar.
When testing the same code on iOS 26, these same views have their content extend under the navigation bar and toolbar. I was able to fix it with:
if #available(iOS 26, *, *) {
self.edgesForExtendedLayout = [.bottom]
}
when running on iOS 26. I also fixed one or two places where the main view was anchored to self.view.topAnchor instead of self.view.safeAreaLayoutGuide.topAnchor.
Although this seems to work, I wonder if this was an intended change in iOS 26 or just a temporary bug in the beta that will be resolved.
Were changes made to the safe area and edgesForExtendedLayout logic in iOS 26? If so, is there a place I can see what the specific changes were, so I know my code is handling it properly?
Thanks!
Topic:
UI Frameworks
SubTopic:
UIKit
All system colors are displayed incorrectly on the popover view.
Those are the same views present as a popover in light and dark mode.
And those are the same views present as modal.
And there is also a problem that when the popover is presented, switching to dark/light mode will not change the appearance. That affected all system apps.
The following screenshot is already in dark mode.
All those problem are occured on iOS 26 beta 3.
Hi, I faced with the issue on iOS 26.1 with PHPickerViewController. After first selection I save assetIdentifier of PHPickerResult for images.
next time I open the picker I expect to have the images selected based on assetIdentifier
Code:
var config = PHPickerConfiguration(photoLibrary: .shared())
config.selectionLimit = 10
config.filter = .images
config.preselectedAssetIdentifiers = images.compactMap(\.assetID)
let picker = PHPickerViewController(configuration: config)
picker.delegate = self
present(picker, animated: true)
But on iOS 26.1 they aren't selected. On lower iOS version all works fine.
Does anybody faced with similar issue?
Topic:
UI Frameworks
SubTopic:
UIKit
For whatever reason SwiftUI sheets don't seem to be resizable anymore.
The exact same code/project produces resizable Sheets in XCode 15.4 but unresizable ones with Swift included in Xcode 16 beta 2.
Tried explicitly providing .fixedSize(horizontal false, vertical: false) everywhere humanly possible hoping for a fix but sheets are still stuck at an awkward size (turns out be the minWidth/minHeight if I provide in .frame).
Hello,
I'm experiencing a navigation bar positioning issue with my UIKit iPad app on iPadOS 26 (23A340) using Xcode 26 (17A321).
The navigation bar positions under the status bar initially, and after orientation changes to landscape, it positions incorrectly below its expected location. This occurs on both real device (iPad mini A17 Pro) and simulator. My app uses UIKit + Storyboard with a Root Navigation Controller.
A stack overflow post has reproduce the bug event if it's not in the same configuration: https://stackoverflow.com/questions/79752945/xcode-26-beta-6-ipados-26-statusbar-overlaps-with-navigationbar-after-presen
I have checked all safe areas and tried changing some constraints, but nothing works.
Have you encountered this bug before, or do you need additional information to investigate this issue?
I want a different color, one from my asset catalog, as the background of my first ever swift UI view (and, well, swift, the rest of the app is still obj.c)
I've tried putting the color everywhere, but it does't take. I tried with just .red, too to make sure it wasn't me. Does anyone know where I can put a color call that will actually run? Black looks very out of place in my happy app. I spent a lot of time making a custom dark palette.
TIA
KT
@State private var viewModel = ViewModel()
@State private var showAddSheet = false
var body: some View {
ZStack {
Color.myCuteBg
.ignoresSafeArea(.all)
NavigationStack {
content
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
Image("cute.image")
.font(.system(size: 30))
.foregroundColor(.beigeTitle)
}
}
}
.background(Color.myCuteBg)
.presentationBackground(.myCuteBg)
.sheet(isPresented: $showAddSheet) {
AddView()
}
.environment(viewModel)
.onAppear {
viewModel.fetchStuff()
}
}
.tint(.cuteColor)
}
@ViewBuilder var content: some View {
if viewModel.list.isEmpty && viewModel.anotherlist.isEmpty {
ContentUnavailableView(
"No Content",
image: "stop",
description: Text("Add something here by tapping the + button.")
)
} else {
contentList
}
}
var contentList: some View {
blah blah blah
}
}
First I tried the background, then the presentation background, and finally the Zstack. I hope this is fixed because it's actually fun to build scrollable content and text with swiftUI and I'd been avoiding it for years.
I've posted a couple times now about major issues I'm having with NSLayoutManager and have written to Apple for code-level support, but no one at Apple has responded to me in more than two weeks. So I'm turning to the community again for any help whatsoever.
I'm fairly certain it's a real bug in TextKit. If I'm right about that, I'd love for anyone at Apple to take an interest. And better yet, if I'm wrong (and I hope I am), I'd be incredibly grateful to anyone who can point out where my mistake lies! I've been stuck with this bug for weeks on end.
The crux of the issue is that I'm getting what seemed to be totally incompatible results from back to back calls to textContainer(forGlyphAt:effectiveRange:) and lineFragmentRect(forGlyphAt:effectiveRange:withoutAdditionalLayout:)... I'd lay out my text into a fairly tall container of standard page width and then query the layout manager for the text container and line fragment rect for a particular glyph (a glyph that happens to fall after many newlines). Impossibly, the layout manager would report that that glyph was in said very tall container, but that the maxY of its lineFragmentRect was only at 14 points (my NSTextView's isFlipped is true, so that's 14 points measuring from the top down).
After investigating, it appears that what is happening under the hood is NSLayoutManager is for some reason laying out text back into the first container in my series of containers, rather than overflowing it into the next container(s) and/or giving me a nil result for textContainer(forGlyphAt:...)
I've created a totally stripped down version of my project that recreates this issue reliably and I'm hoping literally anyone at Apple will respond to me. In order to recreate the bug, I've had to build a very specific set of preview data - namely some NSTextStorage content and a unique set of NSTextViews / NSTextContainers.
Because of the unique and particular setup required to recreate this bug, the code is too much to paste here (my preview data definition is a little unwieldy but the code that actually processes/parses it is not).
I can share the project if anyone is able and willing to look into this with me. It seems I'm not able to share a .zip of the project folder here but am happy to email or share a dropbox link.
[Also submitted as FB19313064]
The .disabled() modifier doesn't visually disable buttons inside a ToolbarItem container on iOS 26.0 (23A5297i) devices. The button looks enabled, but tapping it doesn't trigger the action.
When deployment target is lowered to iOS 18 and deployed to an iOS 18 device, it works correctly. It still fails on an iOS 26 device, even with an iOS 18-targeted build.
This occurs in both the Simulator and on a physical device.
Screen Recording
Code
struct ContentView: View {
@State private var isButtonDisabled = false
private var osTitle: String {
let version = ProcessInfo.processInfo.operatingSystemVersion
return "iOS \(version.majorVersion)"
}
var body: some View {
NavigationStack {
VStack {
Button("Body Button") {
print("Body button tapped")
}
.buttonStyle(.borderedProminent)
.disabled(isButtonDisabled)
Toggle("Disable buttons", isOn: $isButtonDisabled)
Spacer()
}
.padding()
.navigationTitle("Device: \(osTitle)")
.navigationBarTitleDisplayMode(.large)
.toolbar {
ToolbarItem {
Button("Toolbar") {
print("Toolbar button tapped")
}
.buttonStyle(.borderedProminent)
.disabled(isButtonDisabled)
}
}
}
}
}
I need to check the network connection with NWPathMonitor.
import Foundation
import Network
class NetworkViewModel: ObservableObject {
let monitor = NWPathMonitor()
let queue = DispatchQueue(label: "NetworkViewModel")
@Published var isConnected = false
var connectionDescription: String {
if isConnected {
return "You are connected."
} else {
return "You are NOT connected."
}
}
init() {
monitor.pathUpdateHandler = { path in
DispatchQueue.main.async {
self.isConnected = path.status == .satisfied
}
}
monitor.start(queue: queue)
}
}
import SwiftUI
struct ContentView: View {
@StateObject private var networkViewModel = NetworkViewModel()
var body: some View {
VStack {
}
.onAppear {
if networkViewModel.isConnected {
print("You are connected.")
}
else {
print("You are NOT connected.")
}
}
}
}
So there is nothing special, not at all. Yet, if I test it with a totally new Xcode project for iOS, it fails and return !isConnected. I've tested it with a macOS application. And it fails. I've tested it with an actual device. It fails. I've tested it with an old project. It still does work. I have no mere idea why new Xcode projects all fail to detect the WiFi connection. This is a total nightmare. Does anybody have a clue? thanks.
I’m seeing unexpected scroll behavior when embedding a LazyVStack with dynamically sized views inside a ScrollView.
Everything works fine when the item height is fixed (e.g. colored squares), but when I switch to text views with variable height, the scroll position jumps and glitches—especially when the keyboard appears or disappears. This only happens on iOS 26, it works fine on iOS 18.
Working version
struct Model: Identifiable {
let id = UUID()
}
struct ModernScrollView: View {
@State private var models: [Model] = []
@State private var scrollPositionID: String?
@State private var text: String = ""
@FocusState private var isFocused
// MARK: - View
var body: some View {
scrollView
.safeAreaInset(edge: .bottom) { controls }
.task { reset() }
}
// MARK: - Subviews
private var scrollView: some View {
ScrollView {
LazyVStack {
ForEach(models) { model in
SquareView(color: Color(from: model.id))
.id(model.id.uuidString)
}
}
.scrollTargetLayout()
}
.scrollPosition(id: $scrollPositionID)
.scrollDismissesKeyboard(.interactively)
.defaultScrollAnchor(.bottom)
.onTapGesture {
isFocused = false
}
}
private var controls: some View {
VStack {
HStack {
Button("Add to top") {
models.insert(contentsOf: makeModels(3), at: 0)
}
Button("Add to bottom") {
models.append(contentsOf: makeModels(3))
}
Button("Reset") {
reset()
}
}
HStack {
Button {
scrollPositionID = models.first?.id.uuidString
} label: {
Image(systemName: "arrow.up")
}
Button {
scrollPositionID = models.last?.id.uuidString
} label: {
Image(systemName: "arrow.down")
}
}
TextField("Input", text: $text)
.padding()
.background(.ultraThinMaterial, in: .capsule)
.focused($isFocused)
.padding(.horizontal)
}
.padding(.vertical)
.buttonStyle(.bordered)
.background(.regularMaterial)
}
// MARK: - Private
private func makeModels(_ count: Int) -> [Model] {
(0..<count).map { _ in Model() }
}
private func reset() {
models = makeModels(3)
}
}
// MARK: - Color+UUID
private extension Color {
init(from uuid: UUID) {
let hash = uuid.uuidString.hashValue
let r = Double((hash & 0xFF0000) >> 16) / 255.0
let g = Double((hash & 0x00FF00) >> 8) / 255.0
let b = Double(hash & 0x0000FF) / 255.0
self.init(red: abs(r), green: abs(g), blue: abs(b))
}
}
Not working version
When I replace the square view with a text view that generates random multiline text:
struct Model: Identifiable {
let id = UUID()
let text = generateRandomText(range: 1...5)
// MARK: - Utils
private static func generateRandomText(range: ClosedRange<Int>) -> String {
var result = ""
for _ in 0..<Int.random(in: range) {
if let sentence = sentences.randomElement() {
result += sentence
}
}
return result.trimmingCharacters(in: .whitespaces)
}
private static let sentences = [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
]
}
and use it like this:
ForEach(models) { model in
Text(model.text)
.padding()
.multilineTextAlignment(.leading)
.background(Color(from: model.id))
.id(model.id.uuidString)
}
Then on iOS 26, opening the keyboard makes the scroll position jump unpredictably.
It is more visible if you play with the app, but I could not upload a video here.
Environment
Xcode 26.0.1 - Simulators and devices on iOS 26.0 - 18.0
Questions
Is there any known change in ScrollView / scrollPosition(id:) behavior on iOS 26 related to dynamic height content?
Am I missing something in the layout setup that makes this layout unstable with variable-height cells?
Is there a workaround or recommended approach for keeping scroll position stable when keyboard appears?
I am trying to learn Xcode and swift ui for a class project but the attribute inspector just does not show up, I can have the simulator open or closed I click on it nothing works. I feel so stupid. I suppose you don't need it but it helps a lot. anyone have any trouble shooting that could help?
Topic:
UI Frameworks
SubTopic:
SwiftUI
The example code below shows what I am trying to achieve: When the user types a '*', it should be replaced with a '×'.
It looks like it works, but the cursor position is corrupted, even though it looks OK, and the diagnostics that is printed below shows a valid index. If you type "12*34" you get "12×43" because the cursor is inserting before the shown cursor instead of after.
How can I fix this?
struct ContentView: View {
@State private var input: String = ""
@State private var selection: TextSelection? = nil
var body: some View {
VStack {
TextField("Type 12*34", text: $input, selection: $selection)
.onKeyPress(action: {keyPress in
handleKeyPress(keyPress)
})
Text("Selection: \(selectionAsString())")
}.padding()
}
func handleKeyPress(_ keyPress: KeyPress) -> KeyPress.Result {
if (keyPress.key.character == "*") {
insertAtCursor(text: "×")
moveCursor(offset: 1)
return KeyPress.Result.handled
}
return KeyPress.Result.ignored
}
func moveCursor(offset: Int) {
guard let selection else { return }
if case let .selection(range) = selection.indices {
print("Moving cursor from \(range.lowerBound)")
let newIndex = input.index(range.lowerBound, offsetBy: offset, limitedBy: input.endIndex)!
let newSelection : TextSelection.Indices = .selection(newIndex..<newIndex)
if case let .selection(range) = newSelection {
print("Moved to \(range.lowerBound)")
}
self.selection!.indices = newSelection
}
}
func insertAtCursor(text: String) {
guard let selection else { return }
if case let .selection(range) = selection.indices {
input.insert(contentsOf: text, at: range.lowerBound)
}
}
func selectionAsString() -> String {
guard let selection else { return "None" }
switch selection.indices {
case .selection(let range):
if (range.lowerBound == range.upperBound) {
return ("No selection, cursor at \(range.lowerBound)")
}
let lower = range.lowerBound.utf16Offset(in: input)
let upper = range.upperBound.utf16Offset(in: input)
return "\(lower) - \(upper)"
case .multiSelection(let rangeSet):
return "Multi selection \(rangeSet)"
@unknown default:
fatalError("Unknown selection")
}
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
When building with the iOS 26 SDK (currently beta 4), the navigation title is often illegible when rendering a Map view.
For example, note how the title "Choose Location" is obscured by the map's text ("South America") in the screenshot below:
This screenshot is the result of the following view code:
import MapKit
import SwiftUI
struct Demo: View {
var body: some View {
NavigationStack {
Map()
.navigationTitle(Text("Choose Location"))
.navigationBarTitleDisplayMode(.inline)
}
}
}
I tried using the scrollEdgeEffectStyle(_:for:) modifier to apply a scroll edge effect to the top of the screen, in hopes of making the title legible, but that doesn't seem to have any effect. Specifically, the following code seems to produce the exact same result shown in the screenshot above.
import MapKit
import SwiftUI
struct Demo: View {
var body: some View {
NavigationStack {
Map()
.scrollEdgeEffectStyle(.hard, for: .top) // ⬅️ no apparent effect
.navigationTitle(Text("Choose Location"))
.navigationBarTitleDisplayMode(.inline)
}
}
}
Is there a recommended way to resolve this issue so that the navigation title is always readable?