Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

SwiftUI NavigationView pops back when updating observableObject
Background: I have been stuck on this annoying problem for days, trying different solution and searching apple developer forum, stackoverflow etc for answers; some have had similar problems but no suggested solution had the desired effect. The problem is that when updating an observableObject or environmentObject down the navigation hierarchy view stack, the views get popped back to root. Viewing data from observableObject is fine, but not editing. Scenario is: I navigate to: root -> view1 -> view2. I update the environmentObject in View2 but then I get pushed back to: root -> view1 I have simplified my app in order to make it more understandable. See below: ObservableObject: class DataStore: ObservableObject { static let shared = dataStore() @Published var name : Int = "" } RootView: struct ContentView: View { @StateObject var dataStore = DataStore.shared @State private var isShowingView1 = false var body: some View { NavigationView{ VStack{ Text(dataStore.name) NavigationLink(destination: View1(), isActive: $isShowingView1) { } Button(action: { isShowingView1 = true }) } } } } View1: struct View1: View { @EnvironmentObject var dataStore: dataStore @State private var isShowingView2 = false var body: some View { ScrollView{ VStack(alignment: .center) { Text(dataStore.name) NavigationLink(destination: View2(), isActive: $isShowingView2) { } Button(action: { isShowingView2 = true }){ Text("Go to View2") } } } } } View2: struct View2: View { @EnvironmentObject var dataStore: dataStore var body: some View { ScrollView{ VStack(alignment: .center) { Text(dataStore.name) Button(action: { dataStore.name = "updated value" }){ Text("Update data") } // When updating this environmentObject the viewstack will be pushed back to View1. If view2 had been navigated to view3 and the view3 had been updating the environmentObject, then it would also be pushed back to View1. } } } } Solution: I spent many hours searching for solutions and trying different approaches, but nothing I tried worked. There seemed to be a few other people that had the same problem as I experienced, but the suggested solutions didn't cut it. But then I stumbled on a solution for this problem when trying to implement another feature. So to be frank I am writing here now, not to ask this great community for help, but instead to give back to the community by providing the this solution to others that might need to see this. The solution is really simple implement but was not so easy to come across. If you experience a problem similar to me then you will only need to update your rootView accordingly: RootView Updated: struct ContentView: View { @StateObject var dataStore = DataStore.shared @State private var isShowingView1 = false var body: some View { NavigationView{ VStack{ Text(dataStore.name) NavigationLink(destination: View1(), isActive: $isShowingView1) { } Button(action: { isShowingView1 = true }) } } .navigationViewStyle(.stack) //ADD THIS LINE ABOVE } } This one line .navigationViewStyle(.stack) fixed the problem of popping the viewstack for me. Unfortunately I can't provide you with the logic explanation for this behaviour, but it works and I am satisfied with that. Perhaps you are too, or perhaps you have insight on why this solution actually achieves the desired effect of allowing views down the hierarchy update observableObjects without being popped. Happy coding :)
15
13
17k
Oct ’21
SwiftUI and focusedSceneValue on macOS, what am I doing wrong?
I'm trying to understand how to use .focusedSceneValue on macOS. Given a very basic app which displays Thing-s, and have a menu for editing the things. When I run the app, nothing is selected at first and the menu is disabled. When selecting e.g. the Thing Alfa in the sidebar. the menu becomes enabled as expected. When I select another Thing, the menu is also updated as expected. However, if I switch focus to another application, e.g. the Finder, and then switch back to my app, the menu is now disabled, even though a Thing is selected in the sidebar. If I open another window within my app and select e.g. Gamma in the sidebar of that window the menu is updated as expected. But, when switching back to the first window the menu is disabled, although a Thing is selected. What am I doing wrong? Xcode 13.1 and macOS Monterey 12.0.1. See the code below (the code can also be found here: https://github.com/danwaltin/FocusedSceneValueTest) struct Thing: Identifiable, Hashable { let id: Int let name: String static func things() -> [Thing] { return [ Thing(id: 1, name: "Alfa"), Thing(id: 2, name: "Beta"), Thing(id: 3, name: "Gamma") ] } } @main struct FocusedSceneValueTestApp: App { var body: some Scene { WindowGroup { ContentView() } .commands { ThingCommands() } } } struct ContentView: View { var body: some View { NavigationView { List(Thing.things()) { thing in NavigationLink( destination: DetailView(thing: thing), label: {Text(thing.name)} ) } Text("Nothing selected") } } } struct DetailView: View { let thing: Thing var body: some View { Text(thing.name) .focusedSceneValue(\.selectedThing, thing) .navigationTitle(thing.name) } } struct ThingCommands: Commands { @FocusedValue(\.selectedThing) private var thing var body: some Commands { CommandMenu("Things") { Button("Edit \(thingName)") { print("*** Editing \(thingName)") } .disabled(thing == nil) .keyboardShortcut("e") } } private var thingName: String { guard let thing = thing else { return "" } return thing.name } } struct SelectedThingKey : FocusedValueKey { typealias Value = Thing } extension FocusedValues { var selectedThing: Thing? { get {self[SelectedThingKey.self]} set {self[SelectedThingKey.self] = newValue} } }
2
0
1.6k
Oct ’21
WKExtensionsDelegateClassName is Invalid in info.plist
So I am banging my head, I realized my stand along Watch App had a STUPID long name of "App Name - WatchKit App" so I went into my Target and changed the Display Name to "App Name" removing WatchKit App. Well now my app won't validate when uploading to the Appstore. I get the message - Invalid Info.plist key. The key WKExtensionDelegateClassName in bundle App Name.app/Watch/App Name WatchKit App.app is invalid.  My Info.plist has the value of <key>WKExtensionDelegateClassName</key> <string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string> I have confirmed that I have  @WKExtensionDelegateAdaptor(ExtensionDelegate.self) var delegate in my @main for the SwiftUI App. And when I print a few values in my app launch I get the following confirmations: Super Init - ExtensionDelegate Contentview applicationDidFinishLaunching for watchOS Super Init - ExtensionDelegate Optional(My_App_Extension.Setup) Optional(My_App_Extension.Statistics) Optional(My_App_Extension.Other) applicationDidBecomeActive for watchOS update complication I create three classes at launch and print this in the log with print(ExtensionDelegate.shared.Setup as Any) , etc. The other lines are just confirming where I am at app startup. This is a WatchOS8 application and I am running Xcode version Version 13.1 (13A1030d).
2
1
1.2k
Nov ’21
How to toggle CoreData CloudKit sync during App runtime
Hi, I'm currently developing a SwiftUI based app with Core Data and CloudKit sync with the NSPersistentCloudKitContainer. I found different solutions how to toggle CloudKit sync of the Core Data during runtime. The basic idea of these solutions is the following. instantiate a new NSPersistentCloudKitContainer set storeDescription.cloudKitContainerOptions = nil load persistence store Some solutions recommend to restart the app manually to avoid exactly my problem. Issues So far so good. How can I distribute the new viewContext through my app during runtime. In the main App I distributed the viewContext during startup via @Environment(\.managedObjectContext) and it seems not be updated automatically after a reinitialization of NSPersistentCloudKitContainer. var body: some Scene {   WindowGroup {             ContentView()                 .environment(\.managedObjectContext, persistence.container.viewContext)         } } After deactivating the CloudKit sync I receive the following error when I try to add a new entity. [error] warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'TestEntity' so +entity is unable to disambiguate. Any ideas? Regards Sven
5
1
2.3k
Nov ’21
Is it possible to unload/change the PersistenceStore in a SwiftUI App during runtime
Hi, I want to activate/deactivate the CloudKit Sync during App runtime in a user settings view. Basically this works fine. Every time I toggle between the NSPersistentContainer and the NSPersistentCloudKitContainer, I increase the persistence.persistenceContainerReloaded attribute and the whole view hierarchy will be reloaded. Thus all changes are passed through the whole app. During the reload phase I have to load a new persistence store by container.loadPersistentStores(...). Unfortunately, I cannot remove the old persistence store before loading the new one. The app crashes immediately, because the store and viewContext is still in use. Therefore, I just create a new one and trigger the reload. Afterwards every view is using the new viewContext. But somewhere in the background there is still the old persistence store with CloudKit Sync active and pushes every local change to the cloud. Changes on the cloud from other devices are not received anymore. Does someone has any idea, how to correctly unload a PersistentStore (replace NSPersistentCloudKitContainer by NSPersistentContainer) in a SwiftUI based app? @main struct TargetShooterApp: App {     @StateObject var persistence: Persistence = Persistence.shared     var body: some Scene {         WindowGroup {             ContentView()                 .environment(\.managedObjectContext, persistence.container.viewContext)                 .id(persistence.persistenceContainerReloaded)         }     } }
6
2
1.1k
Dec ’21
Use @AppStorage with Arrays
Hey, I know you can write @AppStorage("username") var username: String = "Anonymous" to access a Value, stored In the User Defaults, and you can also overwrite him by changing the value of username. I was wondering if there is any workaround to use @AppStorage with Arrays. Because I don't find anything, but I have a lot of situations where I would use it. Thanks! Max
1
1
930
Dec ’21
How to get upload progress when using "await urlSession.upload()"
How to get upload progress when using: let (data, urlResponse) = try await urlSession.upload( for: urlRequest, from: bodyData, delegate: nil // Something I need here maybe? ) I have tried using: func urlSession( _ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) { print("fractionCompleted : \(Float(totalBytesSent) / Float(totalBytesExpectedToSend))") } Within the same class but it never fires. I specifically want the async / await capability on the upload. I couldn't get the session.uploadTask to work with the await prefix.
2
1
2.1k
Jan ’22
@FetchRequest predicate is ignored if the context changes
I have a simple SwiftUI application with CoreData and two views. One view displays all "Place" objects. You can create new places and you can show the details for the place. Inside the second view you can add "PlaceItem"s to a place. The problem is that, once a new "PlaceItem" is added to the viewContext, the @NSFetchRequest seems to forget about its additional predicates, which I set in onAppear. Then every place item is shown inside the details view. Once I update the predicate manually (the refresh button), only the items from the selected place are visible again. Any idea how this can be fixed? Here's the code for my two views: struct PlaceView: View { @FetchRequest(sortDescriptors: []) private var places: FetchedResults<Place> @Environment(\.managedObjectContext) private var viewContext var body: some View { NavigationView { List(places) { place in NavigationLink { PlaceItemsView(place: place) } label: { Text(place.name ?? "") } } } .toolbar { ToolbarItem(placement: .primaryAction) { Button { let place = Place(context: viewContext) place.name = NSUUID().uuidString try! viewContext.save() } label: { Label("Add", systemImage: "plus") } } } .navigationTitle("Places") } } struct PlaceItemsView: View { @ObservedObject var place: Place @FetchRequest(sortDescriptors: []) private var items: FetchedResults<PlaceItem> @Environment(\.managedObjectContext) private var viewContext func updatePredicate() { items.nsPredicate = NSPredicate(format: "place == %@", place) } var body: some View { NavigationView { List(items) { item in Text(item.name ?? ""); } } .onAppear(perform: updatePredicate) .toolbar { ToolbarItem(placement: .primaryAction) { Button { let item = PlaceItem(context: viewContext) item.place = place item.name = NSUUID().uuidString try! viewContext.save() } label: { Label("Add", systemImage: "plus") } } ToolbarItem(placement: .navigationBarLeading) { Button(action: updatePredicate) { Label("Refresh", systemImage: "arrow.clockwise") } } } .navigationTitle(place.name ?? "") } } struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext var body: some View { NavigationView { PlaceView() } } } Thanks!
2
0
729
Feb ’22
SwiftUI context menu crash on iOS 14.x
I'm getting following crash while opening a context menu in LazyHStack item inside of LazyVStack: "Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UIPreviewTarget requires that the container view is in a window, but it is not. (container: <SwiftUI.HostingScrollView: 0x106876400>)'". Anyone can help me out how to avoid this crash issue ?
3
1
1.3k
Feb ’22
SwiftUI List Separator within NavigationView Problem
I'm note sure if this is well-known-issue or not but it is very odd. The problem can be reproduced with Apple's example code navigationBarItems(leading:trailing:) As you can see, list separators has extra leading space that looks like they are indented for some reason. I test above code with Playground, iPhone 13/15.3.1 they are the same. I did messing around the code and found that applying .navigationBarTitle(), .navigationBarItems() to List causes the problem. They must apply to each List item. Very odd though. This means almost all List sample code that wrapping with NavigationView are WRONG. Here is a fix I found. Although I'm not sure if I can call this is a bug but definitely either document or implementation is wrong. Could anyone explain this?
6
0
4.2k
Mar ’22
What is "focus"?
In iOS 15 SDK you added the new FocusState API in SwiftUI. However there is no discussion or explanation anywhere that I could find, which explains: What exactly is "focus"? What isn't focus? What is the relationship between FocusState and accessibility focus? What is the relationship between whether a SecureField is being edited, and whether it's "focused"? Example: Lets say my tvOS app has an on-screen keyboard, where the user uses the remote's directional controls to move focus around to the letter buttons. To enter their password, they focus the password field, then click the center button to activate it. Now that it's active, they move focus to each letter of their password and click on each one: P... A... S... S... W... R... D... !... then they move focus to the "Submit" button and click. In this case, while the SecureField is being edited, focus moves around to a bunch of different buttons. The point of this example is that, if SecureField had a public "isBeingEdited" property, then it would be TRUE even while the field is not focused. However most Workday's designers interpret "focused" as being totally equivalent to "isBeingEdited" because in a web browser, tabbing out of a field makes it stop being edited. What is Apple's intent here? When not using a remote or physical keyboard or screen-reader, how is focus supposed to relate to whether a field is being edited? Does this relationship change when a user now has a bluetooth keyboard connected and Full Keyboard Access is turned ON? How does this correlate with accessibility focus? I cannot find any documentation from Apple that explains what focus is, or how this is supposed to work in SwiftUI in the various different scenarios where the concept of "focus" is relevant. Do you have a link to something current that explains how it's supposed to work so that we will know if there's a bug? Last question: how can we make the iOS simulator treat the physical keyboard as if it was a bluetooth keyboard to be used for focus-based keyboard navigation?
5
0
2.0k
Apr ’22
SwiftUI Settings scene (Preferences): how call action when closed by user (click on red button or Cmd-W)
Hi, I thought this should be quite easy and maybe I only have tomatoes on my eyes, but I cannot find out how to call an action when the user clicks the red button or use CMD-W to close the Preferences window (= Settings Scene). I use Core Data. In the Preferences, many data structures, which define my system, are changed. I learned, that you shouldn't save too often to avoid performance problems, so now I want to save the Core Data context when the user closes the Preferences window. I tried .onDisappear, onChange of focus etc. but this didn't work. How can I define an action? Any hints are welcome :-)
2
0
1.3k
Apr ’22
FamilyActivityPicker selection seems different from OS
Hi, I've implemented the FamilyActivityPicker and I also noticed that it is the same picker that we get when we go to Setttings > Screen Time > App Limits > Add Limit. When you tap on a given row, it will present all apps that are in that category. If you press the check mark on Category then on the Category row will be updated by showing the checkmark as selected and a "All" text to the right side, and on the app rows from that category the check marks will also be marked as selected. This behavior is not consistent when I implement the FamilyActivityPicker. If I go through the same process the app rows won't be shown as selected. Any suggestions on how to make this work? I'm attaching screen shots to illustrate my point. Settings App My FamilyActivityPicker Implementation
1
1
709
May ’22
ScrollView and prefersDefaultFocus currently incompatible?
Hello, I just wanted to confirm that ScrollView and prefersDefaultFocus are currently not compatible, at least when building for tvOS A simple example:     HStack {       ScrollViewReader { proxy in         ScrollView(.horizontal, showsIndicators: true) {           VStack {             Button(action: {               resetFocus(in: namespace)             }) {               Text("RESET FOCUS")             }             HStack {               ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], id:  \.self) { v in                 Button(action: {}) {                   Text("ABC \(v)")                 }.prefersDefaultFocus(v == 11, in: namespace)               }             }           }.onAppear {             resetFocus(in: namespace)           }                     }       }       .focusScope(namespace)     }   } On load of the view the focus remains on the first button in the HStack. On pressing the RESET FOCUS button focus is applied to the first button visible on the left side of the screen. Am I missing something here? Is this the way these pieces of SwiftUI currently interact? e.g. prefersDefaultFocus has no effect inside a ScrollView? Is there a way to focus a specific item in a ScrollView programmatically? Thanks.
3
0
1.7k
May ’22
Quick Look Preview Extension
I'm trying to add a quick look preview extension to my app. But I can't find any reference on this On a earlier thread (https://developer.apple.com/forums/thread/704155) everyone seems to misunderstand my question. I MEAN THE QUICK LOOK YOU CAN TOGGLE IN FINDER THAT WILL SHOW YOU A PREVIEW OF A DOCUEMNT I don't want to add the tag QuickLook because that's not I want to do.
1
0
536
May ’22
SwiftUI List selection bug
Is there a way to optimize a List in SwiftUI? There is a problem with selection not working properly when the List has many rows. If you scroll to multi-select and up, some rows in the middle are not selected. I have an issue where selecting an unselected row deselects nearby rows. Is there any way for selection to work reliably even for a List of many rows? I would like to find a solution that is stable even when multiple lines are selected, like mail and note, which are the default apps in ios. ps. I am using CoreData. @State var selectedItem = Set<MyEntity>() List(selection: $selectItem){   ForEach(items, id: \.self){ item in     ContactsRow(contactsData: item)   } } .environment(\.editMode, $editMode)
1
0
1.6k
Jun ’22