防止 Realm 在更新对象时覆盖属性
Posted
技术标签:
【中文标题】防止 Realm 在更新对象时覆盖属性【英文标题】:Prevent Realm from overwriting a property when updating an Object 【发布时间】:2015-12-29 17:24:40 【问题描述】:我已经为 ios 中的领域对象设置了一个 REST API。但是,我发现在我的对象中创建最喜欢的标志存在问题。我创建了一个最喜欢的布尔值,但是每次从 API 更新对象时,它都会再次将最喜欢的设置为默认 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)
【问题讨论】:
您是说您不想将favorite
保存在Realm 中吗?如果是这样,请删除 dynamic
,因为动态属性会保存在 Realm 中。
我是说favorite
没有存储在远程数据库中,所以每次打开应用程序都会添加新对象并根据主键id
更新现有对象,它会设置收藏夹将值设置为默认值 (false
)。我可以避免它更新为默认值吗?
这很奇怪。我会假设 Realm 中的 createOrUpdate
方法不会触及字典中未指定的属性。您能否将示例代码包含在您实际将 API 数据保存/更新到 Realm 的位置?
我现在已经添加了。可以说,例如,当用户将pet
添加到收藏夹时,我会更改收藏夹。然后当我从我的rest api中的值更新对象时,它会将收藏更改为默认值
【参考方案1】:
有两种方法可以解决这个问题:
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"]
或者你可以
2。进行部分更新
或者您可以在更新 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 将整个数组转换为对象【参考方案2】:如果你想更明确,还有第三种选择:
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)
【讨论】:
我发现这个选项比接受的答案中的选项更可行。 发现这是最好的解决方案。解决方案 1 不添加对象,解决方案 2 似乎是一个混乱的解决方法。感谢您提供第三个选项! 内部对象怎么可能?例如,如果我用一个列表保存一个对象,并且必须为列表中的每个对象截取保存? 您还可以通过仅传递您希望更新的值的子集以及主键来使用主键部分更新对象。我更新了示例以显示这一点。 想第二个@AntonShkurenko的问题,我们如何拦截和更新每个嵌套对象?【参考方案3】: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. 如果你正在做任何大批量的更新,回顾每个对象是不切实际的,而且肯定会在以后造成痛苦。
我希望这能给需要的人提供另一种选择。
【讨论】:
以上是关于防止 Realm 在更新对象时覆盖属性的主要内容,如果未能解决你的问题,请参考以下文章
在单个 AppDomain 上运行多个应用程序实例时如何防止属性覆盖?
在Swift中使用Realm进行过滤,给我一个对象数组,但是当打印一个属性时,它会给我一个空字符串