realm-swift
realm-swift copied to clipboard
KVO on unmanaged Object @Persisted properties fails
How frequently does the bug occur?
All the time
Description
I have an Object class with many properties. In some cases, I make an unmanaged instance of that class to edit it. In those cases, I also use KVO to determine when certain properties have changed.
When I declared my observed property as @objc dynamic var count: Int = 0
this worked. I recently switched to @Persisted var count: Int = 0
and this no longer works.
This makes sense because KVO requires @objc
and dynamic
. When I add them back @Persisted @objc dynamic var count: Int = 0
I get an exception about Simultaneous access
.
I also tried using Realm’s Key Path Change Listeners but they do not seem to work for unmanaged Objects.
Stacktrace & log output
old model count changed to 1
Simultaneous accesses to 0x600003e717f0, but modification requires exclusive access.
Previous access (a modification) started at libswiftCore.dylib`ReferenceWritableKeyPath._projectMutableAddress(from:) + 1164 (0x18f3c6dd0).
Current access (a modification) started at:
0 libswiftCore.dylib 0x000000018f578ddc swift_beginAccess + 564
1 libswiftCore.dylib 0x000000018f53a300 specialized RawKeyPathComponent._projectMutableAddress<A, B>(_:from:to:isRoot:keepAlive:) + 412
2 libswiftCore.dylib 0x000000018f3c6944 ReferenceWritableKeyPath._projectMutableAddress(from:) + 1164
3 libswiftCore.dylib 0x000000018f3c9d34 _swift_modifyAtReferenceWritableKeyPath_impl + 20
4 libswiftCore.dylib 0x000000018f57cb00 swift_modifyAtReferenceWritableKeyPath + 28
5 realm-persisted-observe 0x00000001024a2780 static Persisted.subscript.getter + 152
6 realm-persisted-observe 0x0000000102134a9c MixedStylesModel.count.getter + 92
7 realm-persisted-observe 0x0000000102134a54 @objc MixedStylesModel.count.getter + 36
8 realm-persisted-observe 0x00000001021332f8 closure #2 in ViewController.observeModels() + 248
9 realm-persisted-observe 0x0000000102133500 thunk for @escaping @callee_guaranteed (@guaranteed MixedStylesModel, @in_guaranteed NSKeyValueObservedChange<Int>) -> () + 24
10 libswiftFoundation.dylib 0x00000001b5bdb778 closure #1 in _KeyValueCodingAndObserving.observe<A>(_:options:changeHandler:) + 292
11 libswiftFoundation.dylib 0x00000001b5bde1f0 specialized NSKeyValueObservation.Helper._swizzle_me_observeValue(forKeyPath:of:change:context:) + 1104
12 libswiftFoundation.dylib 0x00000001b5bdb248 @objc NSKeyValueObservation.Helper._swizzle_me_observeValue(forKeyPath:of:change:context:) + 192
13 Foundation 0x000000018079bba4 NSKeyValueNotifyObserver + 288
14 Foundation 0x000000018079ef80 NSKeyValueDidChange + 352
15 Foundation 0x000000018079b11c NSKeyValueDidChangeWithPerThreadPendingNotifications + 148
16 realm-persisted-observe 0x00000001024a3a44 Persisted.set(_:value:) + 1808
17 realm-persisted-observe 0x00000001024a3900 static Persisted.subscript.setter + 220
18 realm-persisted-observe 0x0000000102134b6c MixedStylesModel.count.setter + 112
19 realm-persisted-observe 0x0000000102134b28 @objc MixedStylesModel.count.setter + 44
20 realm-persisted-observe 0x000000010213356c ViewController.incrementModels() + 332
21 realm-persisted-observe 0x0000000102132934 closure #1 in ViewController.viewDidLoad() + 160
22 libswiftUIKit.dylib 0x00000001b5f80a00 thunk for @escaping @callee_guaranteed (@guaranteed UIAction) -> () + 36
23 UIKitCore 0x0000000184c61308 -[UIAction _performActionWithSender:] + 104
24 UIKitCore 0x0000000184645cd4 -[UIControl _sendActionsForEvents:withEvent:] + 304
25 UIKitCore 0x0000000184642208 -[UIButton _sendActionsForEvents:withEvent:] + 156
26 UIKitCore 0x0000000184645cd4 -[UIControl _sendActionsForEvents:withEvent:] + 428
27 UIKitCore 0x0000000184642208 -[UIButton _sendActionsForEvents:withEvent:] + 156
28 UIKitCore 0x0000000184644554 -[UIControl touchesEnded:withEvent:] + 532
29 UIKitCore 0x0000000184d7f3f0 -[UIWindow _sendTouchesForEvent:] + 1104
30 UIKitCore 0x0000000184d80238 -[UIWindow sendEvent:] + 4352
31 UIKitCore 0x0000000184d595b8 -[UIApplication sendEvent:] + 788
32 UIKit 0x00000001b618c144 -[UIApplicationAccessibility sendEvent:] + 96
33 UIKitCore 0x0000000184de3dac __dispatchPreprocessedEventFromEventQueue + 7576
34 UIKitCore 0x0000000184de6150 __processEventQueue + 6792
35 UIKitCore 0x0000000184ddfafc __eventFetcherSourceCallback + 184
36 CoreFoundation 0x0000000180350208 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
37 CoreFoundation 0x0000000180350060 __CFRunLoopDoSource0 + 200
38 CoreFoundation 0x000000018034f3b4 __CFRunLoopDoSources0 + 256
39 CoreFoundation 0x0000000180349814 __CFRunLoopRun + 744
40 CoreFoundation 0x00000001803490cc CFRunLoopRunSpecific + 572
41 GraphicsServices 0x000000018bf0254c GSEventRunModal + 160
42 UIKitCore 0x0000000184d3b100 -[UIApplication _run] + 992
43 UIKitCore 0x0000000184d3ff50 UIApplicationMain + 112
44 libswiftUIKit.dylib 0x00000001b5f7d0a0 UIApplicationMain(_:_:_:_:) + 100
45 realm-persisted-observe 0x0000000102135468 static UIApplicationDelegate.main() + 104
46 realm-persisted-observe 0x000000010213542c static AppDelegate.$main() + 44
47 realm-persisted-observe 0x0000000102135534 main + 28
Can you reproduce the bug?
Yes, always
Reproduction Steps
https://github.com/smpanaro/realm-persisted-observe
Launch the app and tap Increment. You should see the successful log from the old-style property, then the stack trace from above. See observeModels()
in ViewController.swift
where I've commented out the two approaches that crash when you attempt to observe them.
Version
10.19.0
What SDK flavour are you using?
Local Database only
Are you using encryption?
No, not using encryption
Platform OS and version(s)
iOS 15.0
Build environment
ProductName: macOS
ProductVersion: 12.0
BuildVersion: 21A344
/Applications/Xcode.app/Contents/Developer
Xcode 13.1
Build version 13A1030d
/usr/local/bin/pod
1.11.2
(not in use here)
/bin/bash
GNU bash, version 3.2.57(1)-release (arm64-apple-darwin21)
/opt/homebrew/bin/carthage
0.38.0
(not in use here)
/opt/homebrew/bin/git
git version 2.33.1