DocumentChangeListener.changed called multiple times


#1

Hi, I’m using Couchbase Lite 1.4.1 (Android) and I observed something strange: The callback method changed(ChangeEvent) is calling multiple time for a single update.

I tested that by updating a document within the Sync Gateway UI and I received 4 calls to onChanged. I already checked two things:

  • Is it because multiple revisions are being created: No because the event.getChange().getRevisionId is 4 time the same.
  • Did I registers multiple Listener to a same document: No, every changed call are being made to the same object (I checked that by using System.identityHashCode()

Does somebody knows why is that happening and how to prevent it?

Thanks.


#2

That’s strange; it shouldn’t be happening. Could you look at the backtraces of the 4 calls? If they’re different, post them; that could provide a clue.


#3

I’m seeing the same thing with iOS CBL 1.4.1. The following is for a local change, it’s not replicating.

[[NSNotificationCenter defaultCenter] addObserverForName:kCBLDatabaseChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {

Call 1:
-[MasterViewController viewDidLoad]_block_invoke >>CHANGE docId: -94TlQ7WRDGR7lcDYm53lij revId:11-1e91521d81c5e9d6c00a0846887a44f0

Thread 1 Queue : com.apple.main-thread (serial)
#0 0x0000000104f5cb0d in __35-[MasterViewController viewDidLoad]_block_invoke at /Users/hyling/Documents/ToDoLite-iOS-1.4/ToDoLite/MasterViewController.m:41
#1 0x00000001061b2249 in -[__NSObserver _doit:] ()
#2 0x000000010709aeac in CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER ()
#3 0x000000010709adaa in _CFXRegistrationPost ()
#4 0x000000010709aaf2 in ___CFXNotificationPost_block_invoke ()
#5 0x000000010705c792 in -[_CFXNotificationRegistrar find:object:observer:enumerator:] ()
#6 0x000000010705b90c in _CFXNotificationPost ()
#7 0x000000010502b426 in __42-[CBLDatabase(Internal) postNotification:]_block_invoke at /Users/jenkins/jenkins/workspace/couchbase-lite-ios-builds/couchbase-lite-ios-community/Source/CBLDatabase+Internal.m:842
#8 0x0000000104ff2ada in catchInBlock at /Users/jenkins/jenkins/workspace/couchbase-lite-ios-builds/couchbase-lite-ios-community/Source/API/CBLDatabase.m:141
#9 0x00000001061d21e8 in __NSThreadPerformPerform ()
#10 0x00000001070a2101 in CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION ()
#11 0x0000000107141f71 in __CFRunLoopDoSource0 ()
#12 0x0000000107086a19 in __CFRunLoopDoSources0 ()
#13 0x0000000107085fff in __CFRunLoopRun ()
#14 0x0000000107085889 in CFRunLoopRunSpecific ()
#15 0x000000010cc999c6 in GSEventRunModal ()
#16 0x0000000108a655d6 in UIApplicationMain ()
#17 0x0000000104f5f99f in main at /Users/hyling/Documents/ToDoLite-iOS-1.4/ToDoLite/main.m:14
#18 0x00000001080a1d81 in start ()

Call 2
-[MasterViewController viewDidLoad]_block_invoke >>CHANGE docId: -94TlQ7WRDGR7lcDYm53lij revId:11-1e91521d81c5e9d6c00a0846887a44f0

Thread 1 Queue : com.apple.main-thread (serial)
#0 0x0000000104f5cb0d in __35-[MasterViewController viewDidLoad]_block_invoke at /Users/hyling/Documents/ToDoLite-iOS-1.4/ToDoLite/MasterViewController.m:41
#1 0x000000010629b3bb in __22-[__NSObserver _doit:]_block_invoke ()
#2 0x00000001061a722f in NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK ()
#3 0x00000001061a7091 in -[NSBlockOperation main] ()
#4 0x00000001061a554e in -[__NSOperationInternal _start:] ()
#5 0x00000001061a1577 in __NSOQSchedule_f ()
#6 0x000000010802533d in _dispatch_client_callout ()
#7 0x00000001080305f9 in _dispatch_main_queue_callback_4CF ()
#8 0x00000001070c1e39 in CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE ()
#9 0x0000000107086462 in __CFRunLoopRun ()
#10 0x0000000107085889 in CFRunLoopRunSpecific ()
#11 0x000000010cc999c6 in GSEventRunModal ()
#12 0x0000000108a655d6 in UIApplicationMain ()
#13 0x0000000104f5f99f in main at /Users/hyling/Documents/ToDoLite-iOS-1.4/ToDoLite/main.m:14
#14 0x00000001080a1d81 in start ()


#4

@hyling if you use object: nil when registering an NSNotification observer, you get notifications for all objects, in this case all CBLDatabases. You almost certainly don’t want that, because the replicator opens its own CBLDatabase instances to use in the background, and those are posting the same notifications your own CBLDatabase is.