IceCream: Hangs when there are too many changes
My app gives the user the option to delete all his data and also to restore data from backup files.
When erasing all data, I used realm.deleteAll(). Now that I’m using IceCream, I iterate over all my objects and set isDeleted to true.
Then, when restoring data, I go over a different Realm database and use realm.create() to add it to the current Realm.
Now, using IceCream, if I open my app in two devices at the same time, erase all data and then add it back from a backup file, the app will receive the cloudKitDataDidChangeRemotely hundreds of times and it’ll hang forever, making it unusable and requiring me to force quit.
In these cases I think it would be better to group multiple changes together and sync them on a background thread.
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 18 (16 by maintainers)
@dbmrq I think I’ve gotten something to work (heavily inspired by your branch). I modified the BackgroundWorker to behave slightly differently, so it behaves sort of like a Realm-enabled background dispatch queue. I’ve also changed the SyncEngine such that fetching database changes occurs serially (which could be a problem now that we’re using a background process).
You may want to try this: https://github.com/kitlangton/IceCream/tree/background-sync
I’m going to clean it up a little bit and submit a PR soon.
I am running into the same issue with the one-to-many relationships triggering a cascade of updates for child objects when the parent object changes.
The only solution I have come up with so far is to use foreign key association of parent/child objects. So instead of Dog having an Owner as a stored property it just stores the primary key of an owner and has a convenience property to lookup the Owner by key in the Realm.
Aha! I think I got it now. Looking into it a little further I think my problem is related to using multiple objects with one-to-many relationships.
I have
BookandReadingSessionobjects. A book can have many reading sessions (linked with Realm’sLinkingObjects), and eachReadingSessionhas a singleBook(stored in abookproperty).If I add just
SyncObject<Book>()or justSyncObject<ReadingSession>()to theSyncEngine, everything works fine: I make a change to aBook, get a single notification withzid = BooksZoneand theBookis updated on the other device; I make a change to aReadingSession, get a single notification withzid = ReadingSessionsZoneand theReadingSessionis updated. The problem starts when I add both objects to theSyncEngine. Then, if I make a change to aBook, I get a notification withzid = BooksZoneand, besides that, a notification withzid = ReadingSessionsZonefor everyReadingSessionthat book has. I assume this happens because theReadingSessionhas abookproperty populated with theBookobject, and that object was changed, so it’s like theReadingSessionchanged (but it doesn’t actually need to be updated, because it still belongs to the sameBook, it’s only theBookthat changed).So if I have a
Bookwith 100 reading sessions and I change its title, I should get only one notification withzid = BooksZone, but instead I get 101 notifications: the correct one and 100 others withzid = ReadingSessionsZone, one for each of theBook’s reading sessions. And that’s just the tip of the iceberg, because my reading sessions can also have notes and quotes and those should be synced too. So changing a book triggers notifications for the book and all it’s reading sessions and all the notes and quotes for each one of those reading sessions. This makes the library pretty much unusable with multiple objects. I get hundreds of notifications for every little change and the app freezes in no time.So there are two different problems here. One is that those changes block the interface, which shouldn’t happen. But the second problem is that there shouldn’t actually be that many changes. Let me know if you want me to open a different issue for that.
Also I have no idea how to go about this, I still don’t completely understand how this library works. But if you don’t have the time to fix it I’d appreciate if you could guide me in the right direction so I can try to do it myself.
@kitlangton Fantastic, thank you! I’m on a trip right now, so I won’t be able to try this until after the holidays, but it’s looking great! 🍻
I just used the Time Profiler instrument on my app and triggered the problem. Here’s the result for the main thread:
The worst offenders seem to be
SyncObject.add(record:)andSyncObject.registerLocalDatabase(). Then there are all those Realm functions, but most of them are probably triggered by these two, and I think they could be performed in a background thread.