防止 Realm 在更新对象时覆盖属性

25

我已经在iOS中为realm对象设置了一个REST API。然而,我发现在我的对象中创建收藏标志存在问题。我已经创建了一个favorite布尔值,但每次从API更新对象时,它都会再次将favorite设置为默认false。在这里,我希望这个标志不会被更新,因为收藏只被存储在本地。我该如何实现这一点?

class Pet: Object{
    dynamic var id: Int = 1
    dynamic var title: String = ""
    dynamic var type: String = ""
    dynamic var favorite: Bool = false


    override class func primaryKey() -> String {
        return "id"
    }
}

创建或更新

let pet = Pet()
pet.id = 2
pet.name = "Dog"
pet.type = "German Shephard"


try! realm.write {
    realm.add(pet, update: true)
}

你是说你不想在 Realm 中保存 favorite 吗?如果是这样,请删除 dynamic,因为动态属性会被保存在 Realm 中。 - Abhinav
我是在说 favorite 没有存储在远程数据库中,所以每次打开应用程序并添加新对象并基于主键 id 更新现有对象时,它都会将喜爱值设置为默认值 (false)。我能避免它更新到默认值吗? - Peter Pik
иҝҷеҫҲеҘҮжҖӘгҖӮжҲ‘жң¬д»ҘдёәRealmдёӯзҡ„createOrUpdateж–№жі•дёҚдјҡи§ҰеҸҠеӯ—е…ёдёӯжңӘжҢҮе®ҡзҡ„еұһжҖ§гҖӮжӮЁиғҪеҗҰиҜ·жҸҗдҫӣдёҖдёӢе®һйҷ…е°ҶAPIж•°жҚ®дҝқеӯҳ/жӣҙж–°еҲ°Realmзҡ„зӨәдҫӢд»Јз Ғпјҹ - TiM
我已经添加了它。假设当用户将pet加入收藏夹时,我改变了"favorite"。然后,当我从我的 REST API 中更新对象的值时,它将将"favorite"更改为默认值。 - Peter Pik
3个回答

22

有两种方法可以解决这个问题:

1. 使用被忽略的属性:

您可以告诉 Realm 某个属性不应该被持久化。为了防止您的 favorite 属性被 Realm 持久化,您需要执行以下操作:

class Pet: Object{
    dynamic var id: Int = 1
    dynamic var title: String = ""
    dynamic var type: String = ""
    dynamic var favorite: Bool = false

    override class func primaryKey() -> String {
        return "id"
    }

    override static func ignoredProperties() -> [String] {
       return ["favorite"]
   }
}

或者您可以进行部分更新。

或者您可以在更新Pet对象时明确告诉Realm应该更新哪些属性:

->

或者您可以选择进行部分更新,或者在更新Pet对象时明确告诉 Realm 应该更新哪些属性:

try! realm.write {
  realm.create(Pet.self, value: ["id": 2, "name": "Dog", "type": "German Shepard"], update: true)
}

这种方式将不会改变favorite属性。

结论

这两种方法之间有一个很大的区别:

忽略属性:Realm根本不会存储favorite属性。你需要自己跟踪它们。

部分更新:Realm将会存储'favorite'属性,但是它不会被更新。

我想部分更新是你需要的目的。


在我的情况下,isFavorite 应该被保存,但在从服务器获取响应后不应更新。第二个解决方案也不可行,因为响应是作为数组返回的,我正在使用 Codable 将整个数组转换为对象。 - Johnykutty

22

如果你想更明确一些,还有第三种选择:

3. 检索更新的当前值

// Using the add/update method
let pet = Pet()
pet.id = 2
pet.name = "Dog"
pet.type = "German Shephard"

if let currentObject = realm.object(ofType: Pet.self, forPrimaryKey: 2) {
    pet.favorite = currentObject.favorite
}

try! realm.write {
    realm.add(pet, update: true)
}

// Using the create/update method
var favorite = false
if let currentObject = realm.object(ofType: Pet.self, forPrimaryKey: 2) {
    favorite = currentObject.favorite
}

// Other properties on the pet, such as a list will remain unchanged
try! realm.write {
    realm.create(Pet.self, value: ["id": 2, "name": "Dog", "type": "German Shephard", "favorite": favorite], update: true)
}

2
我觉得这个选项比被接受的答案中的更可行。 - Tiago Veloso
1
我发现这是最好的可行解决方案。解决方案1没有添加这个对象,而解决方案2看起来像是一个混乱的变通方法。感谢第三个选项! - SoundShock
2
如何使用内部对象实现这一点?例如,如果我保存一个带有列表的对象,并且必须拦截列表中每个对象的保存? - Anton Shkurenko
您还可以通过仅传递要更新的部分值以及主键来部分更新具有主键的对象。我已更新示例以显示此操作。 - Adam Fish
想要跟随@AntonShkurenko的问题,我们如何拦截和更新每个嵌套对象? - claramelon
像 @claramelon 一样,我也想知道如何拦截和更新嵌套对象。 - jfredsilva

1

4. NSUserDefaults(或任何其他数据存储)

我遇到了同样的问题,我选择了另一种更传统的选项,将东西保存到另一个数据存储中(NSUserDefaults)。在我的情况下,我正在存储用户上次查看项目的时间,并且在NSUserDefaults中存储这些数据是合适的。我做了以下操作:

首先,为您要存储的对象定义一个唯一键(此处的self是正在查看和呈现的模型对象):

- (NSString *)lastViewedDateKey {
    // Note each item gets a unique key with <className>_<itemId> guaranteeing us uniqueness
    return [NSString stringWithFormat:@"%@_%ld", self.class.className, (long)self.itemId];
}

然后,当用户查看该项时,将键设置为:
- (void)setLastViewedToNow {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:[NSDate date] forKey:self.lastViewedDateKey];
    [userDefaults synchronize];
}

稍后,我会像这样使用它:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSDate *createdOnDate = <passed in from elsewhere>;
NSDate *lastViewedDate = [userDefaults objectForKey:self.lastViewedDateKey];
if (!lastViewedDate || [createdOnDate compare:lastViewedDate] == NSOrderedDescending) {
    ...
}

与上述解决方案不同的是: 1. 没有数据持久性。 2. 这会创建另一个需要定义对象属性的地方,如果忘记每次添加新属性时更新此列表,很可能会导致错误。 3. 如果您正在进行任何大批量更新,则回顾每个对象并不实际,而且肯定会在以后造成麻烦。
我希望这为需要它的人提供了另一种选择。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接