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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

SwiftUI preview failing with failedToGenerateThunkInfo
I have an iOS app by using a swift package to hold most of the logic. However, the previews of SwiftUI views often fail with following error: HumanReadableSwiftError BuildError: failedToGenerateThunkInfo(Error Domain=com.apple.xcbuild Code=19 "could not generate preview info: noTargetBuildGraph" UserInfo={NSLocalizedDescription=could not generate preview info: noTargetBuildGraph}) To reproduce this, please clone https://github.com/pointfreeco/isowords and check for preview of ChangelogView.
10
0
2.9k
May ’21
[SwiftUI] How do I catch the "No image named MYEXAMPLE found in asset catalog" warning? Alternatively, how do I determine if something exists in the asset catalog?
I'm trying to store image data locally and the name of the image is retrieved from an API. In the situation where an image does not exist locally, I want to put a placeholder. Right now it just puts a white background. Whenever I retrieve from the API I get a purple exclamation which is a warning but not an exception. How can I intercept this warning and make it show a placeholder instead? One problem is that Image is not an optional. It just blithely accepts whatever is fed into it which is annoying. Is there a way to query the asset catalog if it contains something?
1
0
878
Jun ’21
AsyncImage - Cancelled Loading before View is Visible
I have been playing around with the new AsyncImage Api in SwiftUI I am using the initialiser that passes in a closure with the AsyncImagePhase, to view why an image may not load, when I looked at the error that is passed in if the phase is failure, the localised description of the error is "Cancelled" but this is happening before the view is being displayed. I am loading these images in a list, I imagine I am probably doing something which is causing the system to decide to cancel the loading, but I cannot see what. Are there any tips to investigate this further?
14
6
10k
Jun ’21
How to declare a TableColumn with nullable field?
How does one declare a TableColumn with a nullable field? I have a Book model with several nullable fields: struct Book: Codable, Equatable, Identifiable { // ... let productURL: String? // ... } This is how I'm trying define the corresponding TableColumn: TableColumn("Product URL", value: \.productURL) { book in Text(String(book.productURL ?? "")) } Though this results in several errors: Referencing initializer 'init(_:value:comparator:content:)' on 'TableColumn' requires that 'Book' inherit from 'NSObject' Referencing initializer 'init(_:value:comparator:content:)' on 'TableColumn' requires that 'Book' inherit from 'NSObject' Referencing initializer 'init(_:value:comparator:content:)' on 'TableColumn' requires the types 'KeyPathComparator' and 'SortDescriptor' be equivalent Referencing initializer 'init(_:value:comparator:content:)' on 'TableColumn' requires the types 'KeyPathComparator' and 'SortDescriptor' be equivalent Other, non-nullable columns work just fine. For example: TableColumn("ID", value: \.id) { book in     Text(String(book.id)) } TableColumn("Slug", value: \.slug) TableColumn("Category", value: \.category) TableColumn("Title", value: \.title) // ...
8
0
3.0k
Aug ’21
Conforming @MainActor class to Codable
How does one add Codable conformance to a class that needs to be isolated to the MainActor? For example, the following code gives compiler errors: @MainActor final class MyClass: Codable { var value: Int enum CodingKeys: String, CodingKey { case value } init(from decoder: Decoder) throws { // <-- Compiler error: Initializer 'init(from:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Decodable' let data = try decoder.container(keyedBy: CodingKeys.self) self.value = try data.decode(Int.self, forKey: .value) } func encode(to encoder: Encoder) throws { // <-- Compiler error: Instance method 'encode(to:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Encodable' var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) } } I'm definitely struggling to get my head around actors and @MainActor at the moment!
1
1
2.9k
Aug ’21
@Published properties and the main thread
I am working on a library, a Swift package. We have quite a few properties on various classes that can change and we think the @Published property wrapper is a good way to annotate these properties as it offers a built-in way to work with SwiftUI and also Combine. Many of our properties can change on background threads and we've noticed that we get a purple runtime issue when setting the value from a background thread. This is a bit problematic for us because the state did change on a background thread and we need to update it at that time. If we dispatch it to the main queue and update it on the next iteration, then our property state doesn't match what the user expects. Say they "load" or "start" something asynchronously, and that finishes, the status should report "loaded" or "started", but that's not the case if we dispatch it to the main queue because that property doesn't update until the next iteration of the run loop. There also isn't any information in the documentation for @Published that suggests that you must update it on the main thread. I understand why SwiftUI wants it on the main thread, but this property wrapper is in the Combine framework. Also it seems like SwiftUI internally could ask to receive the published updates on the main queue and @Published shouldn't enforce a specific thread. One thing we are thinking about doing is writing our own property wrapper, but that doesn't seem to be ideal for SwiftUI integration and it's one more property wrapper that users of our package would need to be educated about. Any thoughts on direction? Is there anyway to break @Published from the main thread?
3
1
4.6k
Sep ’21
iOS App shows blank screen after migrating to SwiftUI Lifecycle
This question was originally posted to StackOverflow, but I found it more suitable to be placed here. Was working on migrating one of my app from AppDelegate lifecycle to SwiftUI lifecycle according to this question. After following all the steps, The simulator simply shows a blank screen (the app does not launch at all): There is no log in the console. However, if the app is removed from the simulator (or device) and reinstalled, it will launch the new SwiftUI lifecycle correctly. So there seems to be some problem with scene caching that causes iOS to be confused after the migration. Am I missing something during the migration?
2
0
2.1k
Sep ’21
Unable to tap SwiftUI menu with XCUITest (ios15)
I have a SwiftUI menu Menu{ .... }, label : { Image(...).accessibility(identifier: "cardMenu") } I used to be able to bring up the menu (before upgrading to xcode 13 (ios15)) like this let app = XCUIApplication() app.launch() app.buttons["cardMenu"].tap() But now i am unable to see the identifier in app.buttons. Can't seem to find the identifier anymore. I've tried looking for the identifier in the other app fields and changing to use text instead of identifer. No luck. These tests used to work prior to the upgrade. Any help would be appreciated
3
1
2.9k
Sep ’21
Jaggy, Laggy, low-fps scrolling on iPhone 13 Pro (Pro Motion Display) for .offset
I created a horizontally scrolling view modifier that essentially wraps the contents and applies a horizontal offset based on a DragGesture GestureState. It looks a little bit like this @GestureState private var dragOffset: CGFloat = 0 content .offset(x: dragOffset, y: 0) .simultaneousGesture(DragGesture(minimumDistance: 20, coordinateSpace: .global) .updating($dragOffset) { (value, gestureState, transaction) in                             gestureState = value.translation.width                         }) The problem I am seeing is that on the Pro Motion Display of the iPhone 13 Pro, the "offset" view does not smoothly slide along with your finger as it drags. Instead is is very jaggy or laggy, probably rendered with maybe 15 fps or so. On the iPhone 11 Pro I used before, the drag is very smooth and on the iOS 15 simulator it is smooth as well. What is wrong here? Thanks for help!
7
2
4.9k
Sep ’21
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.5k
Oct ’21
ImportFromDevicesCommands - The operation couldn’t be completed. (Cocoa error 66563.)
I am trying to use import from iPhone option as shown in WWDC session. I added code  WindowGroup {             ContentView()                 .environment(\.managedObjectContext, persistenceController.container.viewContext)                      }         .commands {             ImportFromDevicesCommands()         } ContentView.swift is  List {                 ForEach(items) { item in                     NavigationLink {                         Text("Item at \(item.timestamp!, formatter: itemFormatter)")                     } label: {                         Text(item.timestamp!, formatter: itemFormatter)                     }                 }                 .onDelete(perform: deleteItems)             }             .importsItemProviders([.image,.png,.jpeg,.rawImage], onImport: { providers in                 print("checking reachability")                 return true             }) The importsItemProviders block itself is not executed and not printing anything. In addition I am getting alert The operation couldn’t be completed. (Cocoa error 66563.) Is there anything to add for making this functionality work ?
3
0
1.5k
Nov ’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.1k
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.2k
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
1k
Dec ’21