realm-swift icon indicating copy to clipboard operation
realm-swift copied to clipboard

KVO on unmanaged Object @Persisted properties fails

Open smpanaro opened this issue 3 years ago • 5 comments

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

smpanaro avatar Nov 06 '21 17:11 smpanaro