onGeometryChange: Assertion failed: Block was expected to execute on queue

Hello! After upgrading to Xcode 16 & Swift 6 & iOS 18 I starting receiveing strange crashes.

Happens randomly in different view and pointing to onGeometryChange action block. I added DispatchQueue.main.async { in hopes it will help but it didn't.

HStack {
...
}
            .onGeometryChange(for: CGSize.self, of: \.size) { value in
                DispatchQueue.main.async {
                    self.width = value.width
                    self.height = value.height
                }
            } 

As far as I understand, onGeometryChange is defined as nonisolated and Swift 6 enforce thread checking for the closures, SwiftUI views are always run on the main thread. Does it mean we can not use onGeometryChangesafely in swiftui?

BUG IN CLIENT OF LIBDISPATCH: Assertion failed: Block was expected to execute on queue [com.apple.main-thread (0x1eacdce40)]
Crashed: com.apple.SwiftUI.AsyncRenderer
0  libdispatch.dylib              0x64d8 _dispatch_assert_queue_fail + 120
1  libdispatch.dylib              0x6460 _dispatch_assert_queue_fail + 194
2  libswift_Concurrency.dylib     0x62b58 <redacted> + 284
3  Grit                           0x3a57cc specialized implicit closure #1 in closure #1 in PurchaseModalOld.body.getter + 4377696204 (<compiler-generated>:4377696204)
4  SwiftUI                        0x5841e0 <redacted> + 60
5  SwiftUI                        0x5837f8 <redacted> + 20
6  SwiftUI                        0x586b5c <redacted> + 84
7  SwiftUICore                    0x68846c <redacted> + 48
8  SwiftUICore                    0x686dd4 <redacted> + 16
9  SwiftUICore                    0x6ecc74 <redacted> + 160
10 SwiftUICore                    0x686224 <redacted> + 872
11 SwiftUICore                    0x685e24 $s14AttributeGraph12StatefulRuleP7SwiftUIE15withObservation2doqd__qd__yKXE_tKlF + 72
12 SwiftUI                        0x95450 <redacted> + 1392
13 SwiftUI                        0x7e438 <redacted> + 32
14 AttributeGraph                 0x952c AG::Graph::UpdateStack::update() + 540
15 AttributeGraph                 0x90f0 AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 424
16 AttributeGraph                 0x8cc4 AG::Subgraph::update(unsigned int) + 848
17 SwiftUICore                    0x9eda58 <redacted> + 348
18 SwiftUICore                    0x9edf70 <redacted> + 36
19 AttributeGraph                 0x148c0 AGGraphWithMainThreadHandler + 60
20 SwiftUICore                    0x9e7834 $s7SwiftUI9ViewGraphC18updateOutputsAsync2atAA11DisplayListV4list_AG7VersionV7versiontSgAA4TimeV_tF + 560
21 SwiftUICore                    0x9e0fc0 $s7SwiftUI16ViewRendererHostPAAE11renderAsync8interval15targetTimestampAA4TimeVSgSd_AItF + 524
22 SwiftUI                        0xecfdfc <redacted> + 220
23 SwiftUI                        0x55c84 <redacted> + 312
24 SwiftUI                        0x55b20 <redacted> + 60
25 QuartzCore                     0xc7078 <redacted> + 48
26 QuartzCore                     0xc52b4 <redacted> + 884
27 QuartzCore                     0xc5cb4 <redacted> + 456
28 CoreFoundation                 0x555dc <redacted> + 176
29 CoreFoundation                 0x55518 <redacted> + 60
30 CoreFoundation                 0x55438 <redacted> + 524
31 CoreFoundation                 0x54284 <redacted> + 2248
32 CoreFoundation                 0x535b8 CFRunLoopRunSpecific + 572
33 Foundation                     0xb6f00 <redacted> + 212
34 Foundation                     0xb6dd4 <redacted> + 64
35 SwiftUI                        0x38bc80 <redacted> + 792
36 SwiftUI                        0x1395d0 <redacted> + 72
37 Foundation                     0xc8058 <redacted> + 724
38 libsystem_pthread.dylib        0x637c _pthread_start + 136
39 libsystem_pthread.dylib        0x1494 thread_start + 8
1 Like

Hmmmmm. Does this help?

// note the addition of `@Sendable`
.onGeometryChange(for: CGSize.self, of: \.size) { @Sendable value in
  DispatchQueue.main.async {
    self.width = value.width
    self.height = value.height
  }
} 

That seems like a bug in SwiftUI, AFAIU action should be called from the main thread (and seems like there is an assertion), but some internal rendering calls the block off main thread, causing the issue — even though you wrap your code in main-queue call, the block itself is invoked initially not on correct queue.

2 Likes

Thanks for the suggestion!
Unfortunately, I can not reproduce the bug. It happens randomly for some users, < 1%. So, it takes a week to release the app and monitor if the crash is still there.
As far as I know, the closure is already sendable without an explicit @Sendable, is there something else?

1 Like

I see it the closure is @escaping, but not @Sendable. Marking this @Sendable will prevent the assupmtion of MainActor, and I believe it could prevent the crash.

However, I also agree this sounds like a SwiftUI bug and should definitely be reported.

2 Likes

Thanks! I will try that

1 Like

The app crashed with the same bug on my device, so it didn't help :slightly_smiling_face:

Huh - I don't get it!

Sorry that wasn't helpful...