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.
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
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?
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?
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)
// ...
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!
Hi,
I'm trying to create a ViewController that extends UIHostingController and host an AttachmentView there. Also, I would like to pass an environment object to the AttachmentView, but I get a compile error because the type of rootView does not match what I specify in UIHostingController.
How can I get this code to compile?
Thanks!
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?
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?
SwiftUI Preview Don't work.
Progress Preparing iPhone Simulator for Previews.
SwiftUI
Xcode version 13.0
macOS Big Sur version 11.6
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
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!
The Build for Previews builds all my targets including the test targets. Is there a way to configure the relevant targets? I do not see an option in the schema editor, and disabling Find Implicit Dependencies has no effect either.
Is there a way to use NSPathControl or something equivalent in SwiftUI on Mac?
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 :)
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}
}
}
Table(tableData) {
ForEach(tableColumns) { item in
TableColumn(item.name) { data in
Text(data.value)
}
}
}
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 ?
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).
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
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)
}
}
}