领域:防止对对象的不必要更新

时间:2022-08-29 00:01:25

I have a setup where I fetch some json data from a server to populate a table. There is a chance that the data has changed, so I fetch all the data each time. I map that data into a Realm object and persist it to the database. A primary ID is used to prevent duplication.

我有一个设置,从服务器获取一些json数据来填充表。数据有可能发生了变化,所以每次我都会取回所有的数据。我将数据映射到一个Realm对象,并将其持久化到数据库。主ID用于防止重复。

I use Realm notifications to keep the tableview/collection view in sync with the datasource. When an server request completes, objects are updated or added to the database, and the views automatically reload.

我使用领域通知来保持表视图/集合视图与数据源同步。当服务器请求完成时,对象将被更新或添加到数据库中,视图将自动重新加载。

The problem is that all of the cells reload because all of the objects in the database get updated, even if they aren't actually any different because I'm just blindly using realm.add(object, update:true). Is there is a good way to prevent updating objects that haven't actually changed so that cell's aren't needlessly reloaded?

问题是,所有的单元格都会重载,因为数据库中的所有对象都会被更新,即使它们实际上没有什么不同,因为我只是盲目地使用领域。添加(对象、更新:真实)。是否有一种好的方法可以防止更新那些实际上没有更改的对象,从而使单元格没有不必要的重新加载?

The solution I tried was to write an extension to Realm's Object class including a function that checks if any objects with the same primary ID exist, compare them, and add/update the Object iff they don't match. However, I have many classes of objects, and I couldn't find a way to get the objects type from the object itself without knowing its class to start with.

我尝试的解决方案是为Realm的对象类编写一个扩展,包括一个函数,该函数检查是否存在具有相同主ID的任何对象,对它们进行比较,并添加/更新它们不匹配的对象iff。但是,我有许多类对象,我无法找到一种方法,在不知道对象的类的情况下从对象本身获取对象类型。

// All subclasses of ServerObject have id as their primaryKey
let object = database.objectForPrimaryKey(type:???, key: self.id)

I do not want to copy the same hunk of check-before-add code to every one of my classes because that's asking for trouble, so I need something that can go in a protocol or extension, or just a completely different way to go about handling the server's response.

我不想将签入前的代码复制到我的每一个类中,因为这会带来麻烦,所以我需要一些可以进入协议或扩展的东西,或者仅仅是一种完全不同的方式来处理服务器的响应。

2 个解决方案

#1


1  

It sounds like you want something along the lines of:

听起来你想要的是:

extension Object {
    public func hasChanges(realm: Realm) -> Bool {
        guard let obj = realm.objectForPrimaryKey(self.dynamicType, key: self["id"])
            else { return true }

        for property in obj.objectSchema.properties {
            let oldValue = obj[property.name]
            let newValue = self[property.name]

            if let newValue = newValue {
                if oldValue == nil || !newValue.isEqual(oldValue) {
                    return true
                }
            } else if oldValue != nil {
                return true
            }
        }
        return false
    }
}

This would be used as:

这将作为:

let obj = MyObjectType()
obj.id = ...;
obj.field = ...;
if obj.hasChanges(realm) {
    realm.add(obj, update: true)
}

#2


0  

For object with nested objects (lists), this modified solution seems to work well.

对于嵌套对象(列表)的对象,这个修改后的解决方案似乎很有效。

// This function is general and can be used in any app
private func hasChanges(realm: Realm) -> Bool {
    guard let obj = realm.objectForPrimaryKey(self.dynamicType, key: self["id"])
        else { return true }

    for property in obj.objectSchema.properties {

        // For lists and arrays, we need to ensure all the entries don't have changes
        if property.type == .Array {
            let list = self.dynamicList(property.name)
            for newEntry in list {
                if newEntry.hasChanges(realm) {
                    return true
                }
            }

        // For all properties that are values and not lists or arrays we can just compare values
        } else {

            let oldValue = obj[property.name]
            let newValue = self[property.name]

            if let newValue = newValue {
                if oldValue == nil || !newValue.isEqual(oldValue) {
                    return true
                }
            } else if oldValue != nil {
                return true
            }
        }
    }
    return false
}

#1


1  

It sounds like you want something along the lines of:

听起来你想要的是:

extension Object {
    public func hasChanges(realm: Realm) -> Bool {
        guard let obj = realm.objectForPrimaryKey(self.dynamicType, key: self["id"])
            else { return true }

        for property in obj.objectSchema.properties {
            let oldValue = obj[property.name]
            let newValue = self[property.name]

            if let newValue = newValue {
                if oldValue == nil || !newValue.isEqual(oldValue) {
                    return true
                }
            } else if oldValue != nil {
                return true
            }
        }
        return false
    }
}

This would be used as:

这将作为:

let obj = MyObjectType()
obj.id = ...;
obj.field = ...;
if obj.hasChanges(realm) {
    realm.add(obj, update: true)
}

#2


0  

For object with nested objects (lists), this modified solution seems to work well.

对于嵌套对象(列表)的对象,这个修改后的解决方案似乎很有效。

// This function is general and can be used in any app
private func hasChanges(realm: Realm) -> Bool {
    guard let obj = realm.objectForPrimaryKey(self.dynamicType, key: self["id"])
        else { return true }

    for property in obj.objectSchema.properties {

        // For lists and arrays, we need to ensure all the entries don't have changes
        if property.type == .Array {
            let list = self.dynamicList(property.name)
            for newEntry in list {
                if newEntry.hasChanges(realm) {
                    return true
                }
            }

        // For all properties that are values and not lists or arrays we can just compare values
        } else {

            let oldValue = obj[property.name]
            let newValue = self[property.name]

            if let newValue = newValue {
                if oldValue == nil || !newValue.isEqual(oldValue) {
                    return true
                }
            } else if oldValue != nil {
                return true
            }
        }
    }
    return false
}