Post

Replies

Boosts

Views

Activity

Reply to iOS 16.1 Crashes when scroll (LazyVStack and LazyVGrid)
Can reproduce this with Xcode Version 15.1 beta 3 (15C5059c) deploying to iPhone 14 Pro running iOS 17.1.1. Make a test project with Apple's LazyVGrid sample code. Launch app in portrait, scroll to bottom, rotate to landscape, rotate to portrait, scroll to top, crash! let columns = [GridItem(.flexible()), GridItem(.flexible())] var body: some View { ScrollView { LazyVGrid(columns: columns) { ForEach(0x1f600...0x1f679, id: \.self) { value in Text(String(format: "%x", value)) Text(emoji(value)) .font(.largeTitle) } } } } private func emoji(_ value: Int) -> String { guard let scalar = UnicodeScalar(value) else { return "?" } return String(Character(scalar)) } id: \.self tut tut Apple sample code developer! (this is not the cause of this crash though).
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Nov ’23
Reply to Heavy Duty Work With Async Await
You need to mark the func as nonisolated if you want a background thread, e.g. nonisolated func startWriteImagesNext() async -> Bool { Because you defined it in a ViewController it inherited the @MainActor which doesn't seem what you want to nonisolated bypasses that. Check the NSViewController/UIViewController header to see its @MainActor annotation. You could also declare the func outside of the ViewController to achieve the same effect, e.g. in a struct that is not marked as @MainActor, or a actor if you want some shared state between all the image tasks.
Topic: Programming Languages SubTopic: Swift Tags:
Feb ’24
Reply to CLMonitor Add region after starting to monitor for event changes
I'm experiencing the same bug with Xcode Version 15.3 and iPhone Simulator 17.4. When the app is launched monitoring events are received but are not received for any regions added while app already running. I noticed this sample (which is some very ropey SwiftUI by the way) shows the bug too so I will include that in my feedback report as the test harness: https://developer.apple.com/documentation/corelocation/monitoring_location_changes_with_core_location
Mar ’24
Reply to CLMonitor Add region after starting to monitor for event changes
I experienced the same bug and have reported it as FB13696956 You can find my report on openradar (the link is not allowed here for some reason?). Another issue I noticed is the for try await events does not throw a cancellation exception when the outer task is cancelled like normal streams do. Please submit your own feedback and reference my report so hopefully it will bring more attention to it so it can be fixed!
Mar ’24
Reply to @Observable does not conform with Equatable (and Hashable)
It's simple to provide conformance using ObjectIdentifier, e.g. import SwiftUI @Observable class ObservableContent: Hashable { var text1 = "Default" var text2 = "" static func == (lhs: ObservableContent, rhs: ObservableContent) -> Bool { lhs === rhs } func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } } struct ContentView: View { @State var observableContent: ObservableContent? var body: some View { Group { if let observableContent { NavigationStack { NavigationLink(value: observableContent) { Text("Navigation Link") } .navigationDestination(for: ObservableContent.self) { content in ObservableContentView(content: content) } } } } .onAppear { if observableContent == nil { observableContent = ObservableContent() } } .onDisappear { observableContent = nil } } } struct ObservableContentView: View { @Bindable var content: ObservableContent var body: some View { Form { TextField("Text1", text: $content.text1) Text(content.text1) } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Apr ’24
Reply to @Observable observation outside of SwiftUI
You can use @Observable outside of SwiftUI with AsyncStream like this: struct CountingService { @Observable class Model { public var count: Int = 0 } let model = Model() static var shared = CountingService() init() { Task { [model] in let modelDidChange = AsyncStream { await withCheckedContinuation { continuation in let _ = withObservationTracking { model.count } onChange: { continuation.resume() } } } var iterator = modelDidChange.makeAsyncIterator() repeat { let x = model.count // do something } while await iterator.next() != nil } } } Or if you want the count in the stream, like this: let countDidChange = AsyncStream { await withCheckedContinuation { continuation in let _ = withObservationTracking { model.count } onChange: { continuation.resume() } } return model.count } for await count in countDidChange { } Inside of SwiftUI, @Observable is only designed for model data, for view data please use the View struct hierarchy with @State structs to model your view data and .task for async/await. You'll avoid consistency issues that way and can use many of the powerful features like environment and preferences which you would lose if you attempt to use classes for view data instead.
Topic: App & System Services SubTopic: General Tags:
May ’24
Reply to Regression in Concurrent Task Execution on macOS 15 Beta: Seeking Clarification
To use async/await from SwiftUI it is .task not Task and to get a background thread for a func declared inside the View struct (which is annotated MainActor) use nonisolated func, e.g. Button(isRunning ? "Stop" : "Run Concurrent Tasks") { results.removeAll() isRunning.toggle() } .task(id: isRunning) { // main thread if isRunning { async let task1 = countingTask(name: "Task 1", target: 1000) } } ... } // without nonisolated it would be main actor and thus always on main thread func nonisolated countingTask(name: String, target: Int) async -> String { // background thread If you moved the func to a custom struct then it wouldn't need nonisolated. If that controller struct was an EnvironmentKey then it could be mocked for Previews.
Topic: Programming Languages SubTopic: Swift Tags:
Aug ’24
Reply to SwiftUI State not reliable updating
onAppear is too late to set state. You should have the state configured first, then body is designed to create all the Views depending on the state. This is a crucial part of SwiftUI's design where "views are a function of state". onAppear is designed for external actions unrelated to state. Since you are using SwiftData it's not @State it is @Query to fetch the models and then bind the Views directly to them. If the types are different you can use computed bindings to convert.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Aug ’24
Reply to iOS 16.1 Crashes when scroll (LazyVStack and LazyVGrid)
Can reproduce this with Xcode Version 15.1 beta 3 (15C5059c) deploying to iPhone 14 Pro running iOS 17.1.1. Make a test project with Apple's LazyVGrid sample code. Launch app in portrait, scroll to bottom, rotate to landscape, rotate to portrait, scroll to top, crash! let columns = [GridItem(.flexible()), GridItem(.flexible())] var body: some View { ScrollView { LazyVGrid(columns: columns) { ForEach(0x1f600...0x1f679, id: \.self) { value in Text(String(format: "%x", value)) Text(emoji(value)) .font(.largeTitle) } } } } private func emoji(_ value: Int) -> String { guard let scalar = UnicodeScalar(value) else { return "?" } return String(Character(scalar)) } id: \.self tut tut Apple sample code developer! (this is not the cause of this crash though).
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Nov ’23
Reply to Heavy Duty Work With Async Await
You need to mark the func as nonisolated if you want a background thread, e.g. nonisolated func startWriteImagesNext() async -> Bool { Because you defined it in a ViewController it inherited the @MainActor which doesn't seem what you want to nonisolated bypasses that. Check the NSViewController/UIViewController header to see its @MainActor annotation. You could also declare the func outside of the ViewController to achieve the same effect, e.g. in a struct that is not marked as @MainActor, or a actor if you want some shared state between all the image tasks.
Topic: Programming Languages SubTopic: Swift Tags:
Replies
Boosts
Views
Activity
Feb ’24
Reply to CLMonitor Add region after starting to monitor for event changes
I'm experiencing the same bug with Xcode Version 15.3 and iPhone Simulator 17.4. When the app is launched monitoring events are received but are not received for any regions added while app already running. I noticed this sample (which is some very ropey SwiftUI by the way) shows the bug too so I will include that in my feedback report as the test harness: https://developer.apple.com/documentation/corelocation/monitoring_location_changes_with_core_location
Replies
Boosts
Views
Activity
Mar ’24
Reply to CLMonitor Add region after starting to monitor for event changes
I experienced the same bug and have reported it as FB13696956 You can find my report on openradar (the link is not allowed here for some reason?). Another issue I noticed is the for try await events does not throw a cancellation exception when the outer task is cancelled like normal streams do. Please submit your own feedback and reference my report so hopefully it will bring more attention to it so it can be fixed!
Replies
Boosts
Views
Activity
Mar ’24
Reply to Console app not showing os_log messages from iOS when not run via Xcode
os_log(.info, "launched") appeared in the Console app (With Action->Include Info Messages checked) for me when using the simulator and launching the app from the home screen. These did not appear: print("launched") os_log("launched") os_log(.debug, "launched") // nothing even with Action->Include Info Debug checked!!!
Replies
Boosts
Views
Activity
Mar ’24
Reply to LaunchOptions.locationKey in didFinishLaunchingWithOptions always nil after Application will be waked up from location
launchOptions is always nil in app delegate if using scene delegates scene delegate launchOptions does not provide access to the significant location launch reason here is a workaround: https://stackoverflow.com/a/78228563/259521
Replies
Boosts
Views
Activity
Mar ’24
Reply to @Observable does not conform with Equatable (and Hashable)
It's simple to provide conformance using ObjectIdentifier, e.g. import SwiftUI @Observable class ObservableContent: Hashable { var text1 = "Default" var text2 = "" static func == (lhs: ObservableContent, rhs: ObservableContent) -> Bool { lhs === rhs } func hash(into hasher: inout Hasher) { hasher.combine(ObjectIdentifier(self)) } } struct ContentView: View { @State var observableContent: ObservableContent? var body: some View { Group { if let observableContent { NavigationStack { NavigationLink(value: observableContent) { Text("Navigation Link") } .navigationDestination(for: ObservableContent.self) { content in ObservableContentView(content: content) } } } } .onAppear { if observableContent == nil { observableContent = ObservableContent() } } .onDisappear { observableContent = nil } } } struct ObservableContentView: View { @Bindable var content: ObservableContent var body: some View { Form { TextField("Text1", text: $content.text1) Text(content.text1) } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Apr ’24
Reply to CLMonitor Add region after starting to monitor for event changes
You need to start a task that listens for events simultaneously to when you add a new region to monitor, that's the only way to grab the first event at the right time. This can be done with task groups.
Replies
Boosts
Views
Activity
May ’24
Reply to @Observable observation outside of SwiftUI
You can use @Observable outside of SwiftUI with AsyncStream like this: struct CountingService { @Observable class Model { public var count: Int = 0 } let model = Model() static var shared = CountingService() init() { Task { [model] in let modelDidChange = AsyncStream { await withCheckedContinuation { continuation in let _ = withObservationTracking { model.count } onChange: { continuation.resume() } } } var iterator = modelDidChange.makeAsyncIterator() repeat { let x = model.count // do something } while await iterator.next() != nil } } } Or if you want the count in the stream, like this: let countDidChange = AsyncStream { await withCheckedContinuation { continuation in let _ = withObservationTracking { model.count } onChange: { continuation.resume() } } return model.count } for await count in countDidChange { } Inside of SwiftUI, @Observable is only designed for model data, for view data please use the View struct hierarchy with @State structs to model your view data and .task for async/await. You'll avoid consistency issues that way and can use many of the powerful features like environment and preferences which you would lose if you attempt to use classes for view data instead.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
May ’24
Reply to Migrating @MainActor ViewModel to @Observable causing error
@Observable is for your model data. For your view data, it's best to model it in the View struct hierarchy and use .task for your async actions.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
May ’24
Reply to Enabling undo with multi-model schema
This worked for me, in ContentView, add: @Environment(\.undoManager) var undoManager and .onChange(of: undoManager, initial: true) { modelContext.undoManager = undoManager }
Replies
Boosts
Views
Activity
Jul ’24
Reply to SwiftUI Scene with a single window on macOS
This works on macOS: Window("SingleWindow", id: "main") { I found your question while searching for how to do it on iPadOS.
Topic: UI Frameworks SubTopic: AppKit Tags:
Replies
Boosts
Views
Activity
Jul ’24
Reply to Querying imported files and folders on iOS using NSMetadataQuery
Same problem here. In .fileImporter I even call startAccessingSecurityScopedResource() and am able to read the file in. But afterwards NSMetadataQueryAccessibleUbiquitousExternalDocumentsScope doesn't find the file when searching for it's name with NSMetadataItemFSNameKey. iOS 17.5.1 (21F90)
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Jul ’24
Reply to Regression in Concurrent Task Execution on macOS 15 Beta: Seeking Clarification
To use async/await from SwiftUI it is .task not Task and to get a background thread for a func declared inside the View struct (which is annotated MainActor) use nonisolated func, e.g. Button(isRunning ? "Stop" : "Run Concurrent Tasks") { results.removeAll() isRunning.toggle() } .task(id: isRunning) { // main thread if isRunning { async let task1 = countingTask(name: "Task 1", target: 1000) } } ... } // without nonisolated it would be main actor and thus always on main thread func nonisolated countingTask(name: String, target: Int) async -> String { // background thread If you moved the func to a custom struct then it wouldn't need nonisolated. If that controller struct was an EnvironmentKey then it could be mocked for Previews.
Topic: Programming Languages SubTopic: Swift Tags:
Replies
Boosts
Views
Activity
Aug ’24
Reply to SwiftUI State not reliable updating
onAppear is too late to set state. You should have the state configured first, then body is designed to create all the Views depending on the state. This is a crucial part of SwiftUI's design where "views are a function of state". onAppear is designed for external actions unrelated to state. Since you are using SwiftData it's not @State it is @Query to fetch the models and then bind the Views directly to them. If the types are different you can use computed bindings to convert.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Aug ’24