ListPublisher callback is called too often and ObjectPublisher callback is never called #327

Closed
opened 2025-12-29 18:25:42 +01:00 by adam · 3 comments
Owner

Originally created by @joeljfischer on GitHub (Apr 13, 2020).

I'm having a very strange issue that I'm sure is user error, but that I haven't been able to solve.

ListPublishers being called too often

I have a table view class that is using a ListPublisher and a cell class that's attempting to use a ObjectPublisher to update itself when the object updates. I thought that the ListPublisher would only be called when the list itself experienced an insert, removal, or change in position, but it seems to be being called whenever a property on any data model it's managing is updated.

self.dataSource = DiffableDataSource.TableViewAdapter<MyDataType>(tableView: self.tableView, dataStack: CoreStoreDefaults.dataStack, cellProvider: { (tableView, indexPath, timer) -> UITableViewCell? in
    let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)!
    (cell as! MyCell).data = data

    return cell
})
listPublisher.addObserver(self) { [weak self] (listPublisher) in
    guard let self = self else { return }

    self.dataSource.apply(listPublisher.snapshot, animatingDifferences: true)
    self.dataSnapshot = listPublisher.snapshot
}

This is being called whenever properties on any data updates and refreshes the list.

Object Publishers not being called

I also noticed that an object publisher was never calling it's updater when a property updated on the object.

observer = data.asPublisher(in: CoreStoreDefaults.dataStack)
observer.addObserver(self, { [weak self] (publisher) in
    self?.currentSnapshot = publisher.snapshot
    if let snapshot = self?.currentSnapshot {
        self?.updateUI(snapshot: snapshot)
    }
})

currentSnapshot = data.asSnapshot()!
updateUI(snapshot: currentSnapshot!)

This is called from the data didSet. However, the observer code is never called, even when data's properties update.

Originally created by @joeljfischer on GitHub (Apr 13, 2020). I'm having a very strange issue that I'm sure is user error, but that I haven't been able to solve. ### ListPublishers being called too often I have a table view class that is using a `ListPublisher` and a cell class that's attempting to use a `ObjectPublisher` to update itself when the object updates. I thought that the `ListPublisher` would only be called when the list itself experienced an insert, removal, or change in position, but it seems to be being called whenever a property on any data model it's managing is updated. ```swift self.dataSource = DiffableDataSource.TableViewAdapter<MyDataType>(tableView: self.tableView, dataStack: CoreStoreDefaults.dataStack, cellProvider: { (tableView, indexPath, timer) -> UITableViewCell? in let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath)! (cell as! MyCell).data = data return cell }) listPublisher.addObserver(self) { [weak self] (listPublisher) in guard let self = self else { return } self.dataSource.apply(listPublisher.snapshot, animatingDifferences: true) self.dataSnapshot = listPublisher.snapshot } ``` This is being called whenever properties on any data updates and refreshes the list. ### Object Publishers not being called I also noticed that an object publisher was never calling it's updater when a property updated on the object. ```swift observer = data.asPublisher(in: CoreStoreDefaults.dataStack) observer.addObserver(self, { [weak self] (publisher) in self?.currentSnapshot = publisher.snapshot if let snapshot = self?.currentSnapshot { self?.updateUI(snapshot: snapshot) } }) currentSnapshot = data.asSnapshot()! updateUI(snapshot: currentSnapshot!) ``` This is called from the `data` `didSet`. However, the observer code is never called, even when `data`'s properties update.
adam closed this issue 2025-12-29 18:25:42 +01:00
Author
Owner

@skytoup commented on GitHub (Apr 14, 2020):

About Object Publishers not being called

Today I ran into the same problem as you, after some debugging, I found a snapshot in ObjectPublisher:225 that was lazy loading, and only started monitoring the data changes at initialization.

so....

observer = data.asPublisher(in: CoreStoreDefaults.dataStack)
observer.addObserver(self, { [weak self] (publisher) in
    self?.currentSnapshot = publisher.snapshot
    if let snapshot = self?.currentSnapshot {
        self?.updateUI(snapshot: snapshot)
    }
})

_ = observer.snapshot // let snapshot init and start observe the object change

currentSnapshot = data.asSnapshot()!
updateUI(snapshot: currentSnapshot!)
@skytoup commented on GitHub (Apr 14, 2020): About `Object Publishers not being called` Today I ran into the same problem as you, after some debugging, I found a snapshot in ObjectPublisher:225 that was lazy loading, and only started monitoring the data changes at initialization. so.... ``` observer = data.asPublisher(in: CoreStoreDefaults.dataStack) observer.addObserver(self, { [weak self] (publisher) in self?.currentSnapshot = publisher.snapshot if let snapshot = self?.currentSnapshot { self?.updateUI(snapshot: snapshot) } }) _ = observer.snapshot // let snapshot init and start observe the object change currentSnapshot = data.asSnapshot()! updateUI(snapshot: currentSnapshot!) ```
Author
Owner

@joeljfischer commented on GitHub (Apr 14, 2020):

@skytoup Interesting, thanks for pointing that out! Perhaps removing the lazy load will fix the issue. If the first part of my issue is resolved this will be helpful. I changed to use ObjectMonitor in a few places, which is working well for me for now.

@joeljfischer commented on GitHub (Apr 14, 2020): @skytoup Interesting, thanks for pointing that out! Perhaps removing the lazy load will fix the issue. If the first part of my issue is resolved this will be helpful. I changed to use `ObjectMonitor` in a few places, which is working well for me for now.
Author
Owner

@JohnEstropia commented on GitHub (Apr 15, 2020):

Thanks for the input on this. It is true that the publisher observation starts on first access of snapshot.
Nonetheless, once you have the publisher instance, there is very little reason to use the CoreStoreObject instance, so this is a bit of an antipattern:

currentSnapshot = data.asSnapshot()!

This would have been written as

currentSnapshot = observer.snapshot
updateUI(snapshot: currentSnapshot!)

Another thing I am wondering is where do you get data? If you are planning to use ObjectPublishers I recommend to reserve CoreStoreObject access entirely for background updates.

All that said, the lazy initialization of observers should be triggered from addObserver as well, so I'll make a fix on the next update.

@JohnEstropia commented on GitHub (Apr 15, 2020): Thanks for the input on this. It is true that the publisher observation starts on first access of `snapshot`. Nonetheless, once you have the publisher instance, there is very little reason to use the `CoreStoreObject` instance, so this is a bit of an antipattern: ```swift currentSnapshot = data.asSnapshot()! ``` This would have been written as ``` currentSnapshot = observer.snapshot updateUI(snapshot: currentSnapshot!) ``` Another thing I am wondering is where do you get `data`? If you are planning to use `ObjectPublisher`s I recommend to reserve `CoreStoreObject` access entirely for background updates. All that said, the lazy initialization of observers should be triggered from `addObserver` as well, so I'll make a fix on the next update.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore-JohnEstropia#327