SwiftData and async functions

Hello,

I recently published an app that uses Swift Data as its primary data storage. The app uses concurrency, background threads, async await, and BLE communication.

Sadly, I see my app incurs many fringe crashes, involving EXC_BAD_ACCESS, KERN_INVALID_ADDRESS, EXC_BREAKPOINT, etc.

I followed these guidelines:

  1. One ModelContainer that is stored as a global variable and used throughout.
  2. ModelContexts are created separately for each task, changes are saved manually, and models are not passed around.
  3. Threads with different ModelContexts might manipulate and/or read the same data simultaneously.

I was under the impression this meets the usage requirements.

I suspect perhaps the issue lies in my usage of contexts in a single await function, that might be paused and resumed on a different thread (although same execution path). Is that the case? If so, how should SwiftData be used in async scopes?

Is there anything else particularly wrong in my approach?

The guidelines you described don't have anything obvious wrong, but that isn't quite helpful on diagnosing the crashes.

If you can provide a minimal project that reproduces a crash, I may be able to take a look and comment. A symbolicated crash report may help as well, if you don't have a reproducible case.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

As you suspected, I unfortunately don’t have a reproducible case, as this appears to be a rare race condition (though it has affected approximately 250 of my users).

Here’s an example of the most frequent crash (truncated; full stack trace attached):

          Crashed: com.apple.main-thread
0  libsystem_kernel.dylib         0xc2d4 __pthread_kill + 8
1  libsystem_pthread.dylib        0x859c pthread_kill + 268
2  libsystem_c.dylib              0x77b08 abort + 128
3  libswiftCore.dylib             0x3ccae4 swift::fatalError(unsigned int, char const*, ...) + 134
4  libswiftCore.dylib             0x3ccb04 swift::warningv(unsigned int, char const*, char*) + 30
5  libswiftCore.dylib             0x3c66cc tryCastFromClassToObjCBridgeable(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool) + 254
6  libswiftCore.dylib             0x3c8408 tryCastToObjectiveCClass(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool) + 88
7  libswiftCore.dylib             0x3c5d30 tryCast(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool) + 992
8  libswiftCore.dylib             0x3c57dc swift_dynamicCast + 208
9  SwiftUI                        0x91540 PlatformViewHost.updateNestedHosts(_:colorSchemeChanged:) + 332
10 SwiftUI                        0x91110 PlatformViewHost.updateEnvironment(_:viewPhase:) + 272
11 SwiftUI                        0x27f148 specialized PlatformViewHost.init(_:host:environment:viewPhase:importer:) + 1288
12 SwiftUI                        0x27ec28 specialized PlatformViewHost.__allocating_init(_:host:environment:viewPhase:importer:) + 92
13 SwiftUI                        0x27eb88 closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 504
14 SwiftUI                        0x27e984 partial apply for closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 48
15 SwiftUI                        0x27e90c RepresentableContextValues.asCurrent<A>(do:) + 188
16 SwiftUI                        0x27e804 closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 176
17 SwiftUI                        0x27e72c partial apply for closure #4 in closure #1 in PlatformViewChild.updateValue() + 128
18 SwiftUICore                    0x1640c partial apply for closure #1 in _withObservation<A>(do:) + 48
19 SwiftUICore                    0x14148 closure #1 in _withObservation<A>(do:)partial apply + 16
20 SwiftUICore                    0x128c8 withUnsafeMutablePointer<A, B, C>(to:_:) + 160
21 SwiftUICore                    0x7c08c StatefulRule.withObservation<A>(do:) + 872
22 SwiftUICore                    0x7bb8c StatefulRule.withObservation<A>(do:) + 72
...

There’s no reference to any specific code of mine—no clues at all. How would you recommend I tackle this crash?

          Crashed: com.apple.main-thread

0  libsystem_kernel.dylib         0xc2d4 __pthread_kill + 8

1  libsystem_pthread.dylib        0x859c pthread_kill + 268

2  libsystem_c.dylib              0x77b08 abort + 128

3  libswiftCore.dylib             0x3ccae4 swift::fatalError(unsigned int, char const*, ...) + 134

4  libswiftCore.dylib             0x3ccb04 swift::warningv(unsigned int, char const*, char*) + 30

5  libswiftCore.dylib             0x3c66cc tryCastFromClassToObjCBridgeable(swift::OpaqueValue*, swift::TargetMetadata const*, swift::OpaqueValue*, swift::TargetMetadata const*, swift::TargetMetadata const*&, swift::TargetMetadata const*&, bool, bool) + 254

6  libswiftCore.dylib             0x3c8408 tryCastToObjectiveCClass(swift::OpaqueValue*, swift::TargetMetadata const*, swift::OpaqueValue*, swift::TargetMetadata const*, swift::TargetMetadata const*&, swift::TargetMetadata const*&, bool, bool) + 88

7  libswiftCore.dylib             0x3c5d30 tryCast(swift::OpaqueValue*, swift::TargetMetadata const*, swift::OpaqueValue*, swift::TargetMetadata const*, swift::TargetMetadata const*&, swift::TargetMetadata const*&, bool, bool) + 992

8  libswiftCore.dylib             0x3c57dc swift_dynamicCast + 208

9  SwiftUI                        0x91540 PlatformViewHost.updateNestedHosts(_:colorSchemeChanged:) + 332

10 SwiftUI                        0x91110 PlatformViewHost.updateEnvironment(_:viewPhase:) + 272

11 SwiftUI                        0x27f148 specialized PlatformViewHost.init(_:host:environment:viewPhase:importer:) + 1288

12 SwiftUI                        0x27ec28 specialized PlatformViewHost.__allocating_init(_:host:environment:viewPhase:importer:) + 92

13 SwiftUI                        0x27eb88 closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 504

14 SwiftUI                        0x27e984 partial apply for closure #1 in closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 48

15 SwiftUI                        0x27e90c RepresentableContextValues.asCurrent<a>(do:) + 188

16 SwiftUI                        0x27e804 closure #1 in closure #4 in closure #1 in PlatformViewChild.updateValue() + 176

17 SwiftUI                        0x27e72c partial apply for closure #4 in closure #1 in PlatformViewChild.updateValue() + 128

18 SwiftUICore                    0x1640c partial apply for closure #1 in _withObservation</a><a>(do:) + 48

19 SwiftUICore                    0x14148 closure #1 in _withObservation</a><a>(do:)partial apply + 16

20 SwiftUICore                    0x128c8 withUnsafeMutablePointer(to:_:) + 160

21 SwiftUICore                    0x7c08c StatefulRule.withObservation</a><a>(do:) + 872

22 SwiftUICore                    0x7bb8c StatefulRule.withObservation</a><a>(do:) + 72

23 SwiftUI                        0x8f374 closure #1 in PlatformViewChild.updateValue() + 3312

24 SwiftUICore                    0x204360 Signpost.traceInterval</a><a>(object:_:_:closure:) + 452

25 SwiftUI                        0x791ac PlatformViewChild.updateValue() + 176

26 SwiftUI                        0x78414 partial apply for implicit closure #1 in closure #1 in closure #1 in Attribute.init</a><a>(_:) + 32

27 AttributeGraph                 0xccac AG::Graph::UpdateStack::update() + 540

28 AttributeGraph                 0xc870 AG::Graph::update_attribute(AG::data::ptr, unsigned int) + 424

29 AttributeGraph                 0x3bf4 AG::Graph::input_value_ref_slow(AG::data::ptr, AG::AttributeID, unsigned int, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 720

30 AttributeGraph                 0x3794 AGGraphGetValue + 228

31 SwiftUI                        0x20b90 InvalidatableLeafLayoutComputer.view.getter + 60

32 SwiftUI                        0x363878 RemoteSheetContainerVCWriter.value.getter + 404

33 SwiftUI                        0x360e0 implicit closure #1 in closure #1 in closure #1 in Attribute.init</a><a>(_:) + 324

34 AttributeGraph                 0xccac AG::Graph::UpdateStack::update() + 540

35 AttributeGraph                 0xc870 AG::Graph::update_attribute(AG::data::ptr, unsigned int) + 424

36 AttributeGraph                 0x3bf4 AG::Graph::input_value_ref_slow(AG::data::ptr, AG::AttributeID, unsigned int, unsigned int, AGSwiftMetadata const*, unsigned char&, long) + 720

37 AttributeGraph                 0x3794 AGGraphGetValue + 228

38 SwiftUICore                    0xae908 closure #1 in PairPreferenceCombiner.value.getter + 84

39 SwiftUI                        0x1ade44 protocol witness for static PreferenceKey.reduce(value:nextValue:) in conformance RemoteSheetContainerVCKey + 160

40 SwiftUICore                    0xada80 PairPreferenceCombiner.value.getter + 216

41 SwiftUICore                    0x4cb0 implicit closure #1 in closure #1 in closure #1 in Attribute.init</a><a>(_:) + 324

42 AttributeGraph                 0xccac AG::Graph::UpdateStack::update() + 540

43 AttributeGraph                 0xc870 AG::Graph::update_attribute(AG::data::ptr, unsigned int) + 424

44 AttributeGraph                 0xbfd4 AG::Graph::value_ref(AG::AttributeID, unsigned int, AGSwiftMetadata const*, unsigned char&) + 288

45 AttributeGraph                 0x37e4 AGGraphGetValue + 308

46 SwiftUI                        0x31d664 closure #1 in PresentationHostingController._remoteSheet.getter + 96

47 SwiftUI                        0x31d5fc partial apply for closure #1 in PresentationHostingController._remoteSheet.getter + 20

48 SwiftUICore                    0x79184 closure #1 in static Update.ensure</a><a>(_:) + 56

49 SwiftUICore                    0x79108 static Update.ensure</a><a>(_:) + 100

50 SwiftUI                        0x31d860 PresentationHostingController._remoteSheet.getter + 264

51 SwiftUI                        0x31d730 @objc PresentationHostingController._remoteSheet.getter + 28

52 UIKitCore                      0x356b20 -[UISheetPresentationController _expectedRemoteSheet] + 244

53 UIKitCore                      0x3553b0 -[UISheetPresentationController presentationTransitionWillBegin] + 1124

54 UIKitCore                      0x36d4cc -[_UIFormSheetPresentationController presentationTransitionWillBegin] + 56

55 UIKitCore                      0x36bd5c __80-[UIPresentationController _initViewHierarchyForPresentationSuperview:inWindow:]_block_invoke + 2136

56 UIKitCore                      0x3111c4 __77-[UIPresentationController runTransitionForCurrentStateAnimated:handoffData:]_block_invoke_3 + 304

57 UIKitCore                      0x9fd40 -[_UIAfterCACommitBlock run] + 72

58 UIKitCore                      0x9f894 -[_UIAfterCACommitQueue flush] + 164

59 UIKitCore                      0x9f7a8 _runAfterCACommitDeferredBlocks + 260

60 UIKitCore                      0x9f4c8 _cleanUpAfterCAFlushAndRunDeferredBlocks + 80

61 UIKitCore                      0x9f3d8 _UIApplicationFlushCATransaction + 72

62 UIKitCore                      0x9c890 __setupUpdateSequence_block_invoke_2 + 332

63 UIKitCore                      0x9c704 _UIUpdateSequenceRun + 84

64 UIKitCore                      0x9f034 schedulerStepScheduledMainSection + 172

65 UIKitCore                      0x9cc50 runloopSourceCallback + 92

66 CoreFoundation                 0x73f3c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28

67 CoreFoundation                 0x73ed0 __CFRunLoopDoSource0 + 176

68 CoreFoundation                 0x76b30 __CFRunLoopDoSources0 + 244

69 CoreFoundation                 0x75d2c __CFRunLoopRun + 840

70 CoreFoundation                 0xc8274 CFRunLoopRunSpecific + 588

71 GraphicsServices               0x14c0 GSEventRunModal + 164

72 UIKitCore                      0x3ee77c -[UIApplication _run] + 816

73 UIKitCore                      0x14e64 UIApplicationMain + 340

74 SwiftUI                        0x292660 closure #1 in KitRendererCommon(_:) + 168

75 SwiftUI                        0x292590 runApp</a><a>(_:) + 100

76 SwiftUI                        0x292474 static App.main() + 180

77 MyApp                         0x19d82c main + 4335982636 (MyApp.swift:4335982636)

78 ???                            0x1adb84de8 (Missing)</a>

Your partial crash report indicates that the crash was because of a fatal error Swift triggered when it failed to cast an object, which seemed to be a SwiftUI environment, to an objective C bridgeable. There is no clue related to what the object is unfortunately.

A type casting error may happen because of the object in the memory was corrupted, and so you might consider starting with general memory management diagnostics, as described here.

Considering that environment objects are completely managed by SwiftUI, I’d also suggest that you file a feedback report with several full symbolicated crash reports. If you do so, please share your report ID here. I might take another look to see if the full reports have something interesting.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

SwiftData and async functions
 
 
Q