Search code examples
iosarraysswiftrealm

How to remove all models that are not contained in the current array in Realm


I have the following case, I get data when loading the application, it is an array of ChatUserPersonalConversationModel models, I store this array in Realm as a separate model. What is the best way to do the following when I get an array and if the previous model is not contained in the resulting array, then I delete it from Realm.

I wrote the following code, it works for me, but I think that it can do better.

 func updateChatUserPersonalConversationModels(_ chatUserPersonalConversationModels: [ChatUserPersonalConversationModel]) {
        DispatchQueue.main.async {
            do {
                let realm = try Realm()
                let existChatUserPersonalConversationModels = realm.objects(ChatUserPersonalConversationModel.self)

                for existChatUserPersonalConversationModel in existChatUserPersonalConversationModels {
                    if !chatUserPersonalConversationModels.contains(where: { (newChatUserPersonalConversationModel) -> Bool in
                        return newChatUserPersonalConversationModel.id == existChatUserPersonalConversationModel.id
                    }) {
                        try realm.write {
                            realm.delete(existChatUserPersonalConversationModel)
                        }
                    }
                }

                try realm.write {
                    realm.add(chatUserPersonalConversationModels, update: true)
                }
            } catch {
                debugPrint(error.localizedDescription)
            }
        }
    }

Solution

  • Realm doesn't have any built-in functionality to achieve what you want. An alternative to what you have is to leverage Swift's Set type.

    First, you should make sure equality and the hash value property are defined for your model class, and you should probably have a primary key (which seems to be id).

    Next, turn your arrays of existing and new models into Sets. Set has an initializer that takes any sequence of objects, so you can pass arrays and Realm Lists alike into it.

    Next, use the subtract(_:) method on Set to get a new set containing just the elements you want to delete:

    // itemsToDelete contains models in oldModels that aren't in newModels
    let itemsToDelete = oldModels.subtract(newModels)
    

    Finally, you can use the Realm delete(_:) method that takes a sequence to delete all the obsolete models at once:

    try! realm.write {
        realm.delete(itemsToDelete)
    }
    

    I hope this helps. Note that this isn't a panacea; if your arrays are huge you may want to consider whether this approach uses too much memory.