如何在 Realm Swift 中更新对象

Posted

技术标签:

【中文标题】如何在 Realm Swift 中更新对象【英文标题】:How to update an object in Realm Swift 【发布时间】:2017-09-23 03:51:24 【问题描述】:

我正在尝试学习如何使用 Realm Swift 和 Charts,这样我最终可以在我正在构建的应用程序中同时使用它们,而且我在搞清楚 Realm 时遇到了很多麻烦。最终,我计划让 Charts 查看我的 Realm DB,然后根据数据显示图表,但在此之前,我需要检查一个领域对象是否存在,如果不存在,则创建它,然后在用户使用应用程序时将“计数”添加到该记录并相应地更新图表。

在学习过程中,我已将其分解为多个步骤。我已经想出了如何检查记录是否存在,如果不存在,则像这样构建它:

我的领域模型:

class WorkoutsCount: Object    
    dynamic var date: Date = Date()
    dynamic var count: Int = Int(0)


// function to check if this weeks days have been created in Realm DB yet and creates them if not
    let realm = try! Realm()
    lazy var workouts: Results<WorkoutsCount> =  self.realm.objects(WorkoutsCount.self)()
    let startOfWeekDate = Date().startOfWeek(weekday: 1)
    let nextDay = 24 * 60 * 60
          
    // checks the DB to see if it contains the start of this week
    func searchForDB(findDate: Date) -> WorkoutsCount?
        let predicate = NSPredicate(format: "date = %@", findDate as CVarArg)
        let dateObject = self.realm.objects(WorkoutsCount.self).filter(predicate).first
        
        if dateObject?.date == findDate
            return dateObject
        
        return nil
    

    func setThisWeeksDays()
        //if the beginning of this week doesn't exist in the DB then create each day with 0's as the count data
        if searchForDB(findDate: startOfWeekDate) == nil
            try! realm.write() 
                
                let defaultWorkoutDates = [startOfWeekDate, startOfWeekDate + TimeInterval(nextDay), startOfWeekDate + TimeInterval(nextDay*2), startOfWeekDate + TimeInterval(nextDay*3), startOfWeekDate + TimeInterval(nextDay*4), startOfWeekDate + TimeInterval(nextDay*5), startOfWeekDate + TimeInterval(nextDay*6)]
                
                for workouts in defaultWorkoutDates 
                    let newWorkoutDate = WorkoutsCount()
                    newWorkoutDate.date = workouts
                    self.realm.add(newWorkoutDate)
                
                        
            workouts = realm.objects(WorkoutsCount.self)
        
    

我已经通过 Realm Browser 应用验证了他的工作。

我的待办事项列表中的下一步是弄清楚如何更新“今天的日期记录”的记录。为此,我创建了一个按钮,因此当点击它时会尝试执行此操作。我一直在谷歌搜索和谷歌搜索,并开始认为,由于我没有在我的模型中使用主键,我必须首先删除有问题的特定记录,然后用新数据再次添加它。我一生都无法根据 Realm 文档甚至更多的谷歌搜索来弄清楚如何做到这一点。这就是我所拥有的,虽然它不起作用:

@IBAction func btnUpdate1MW(_ sender: Any) 
        if searchForDB(findDate: today) != nil
            if plusOne <= 7
                plusOne += 1
                CounterImage1MW.image = UIImage(named:  "1MWs-done-\(plusOne)")
                
                let realm:Realm = try! Realm()
                
                // deletes the original item prior to being updated and added back below
                let removeTodaysItem = today
                let workout = realm.objects(WorkoutsCount.self).filter("date = '\(removeTodaysItem)'")
                if workout.count > 0
                    for date in workout
                        try! realm.write 
                            realm.delete(date)
                        
                    
                
                // adds back the item with an updated count
                do 
                    let realm = try Realm()
                    try realm.write 
                        realm.create(WorkoutsCount.self, value: ["date": today, "count": plusOne], update: false)
                    
                 catch let error as NSError 
                    fatalError(error.localizedDescription)
                
            

            print("add to 1MW + 1")
        
    

当我点击 btnUpdate1MW 按钮时,我在 Xcode 中收到以下错误:

由于未捕获的异常“无效值”而终止应用程序,原因:“WorkoutsCount”类型对象上属性“日期”的预期类型日期对象,但收到:2017-04-24 07:00:00 +0000 '

【问题讨论】:

为什么不使用主键?当您想要更新现有对象时,它正是为这些场景而设计的。它比删除和重新创建对象更容易使用,也是一种更优化的解决方案。 因为当返回并添加主键时,它破坏了我已经工作的内容,在上面第一组代码中的“let realm = try!Realm()”行中出错,并且我不知道如何解决这个问题。由于我花了一天的时间来完成这项工作,感觉就像我在倒退了一步。 您是否在您的 AppDelegate、applicationDidFinishLaunching 方法中添加了迁移块?如果不是,这就是您收到错误的原因,并且每次更改 Realm 模型时都会收到相同的错误。 【参考方案1】:

更新对象只是为写入事务中的属性分配一个值。请参阅我们的文档。

https://realm.io/docs/swift/latest/#updating-objects

所以你不需要删除然后添加一个对象。只需在写入事务中为属性分配新值,如下所示。

let workouts = realm.objects(WorkoutsCount.self).filter("date = %@", removeTodaysItem)

let realm = try! Realm()
if let workout = workouts.first 
    try! realm.write 
        workout.date = today
        workout.count = plusOne
    

仅供参考:请不要在查询中使用字符串插值。通常通过字符串插值构造一个重要的字符串是不好的做法。使用 NSPredicate 的字符串替换语法,例如 filter("date = %@", removeTodaysItem)

【讨论】:

有没有办法设置 'workouts' 变量,以便它使用 CONTAIN 过滤我一直无法弄清楚该语法,因为我一直在尝试使用谓词并且文档是'也不清楚让我弄清楚......我也知道'不要使用字符串插值'位,但我很绝望,这些是我在网上找到的例子,但感谢澄清:) 在我的情况下,我收到错误消息锻炼是一个让。所以不能用那个方法改变属性。【参考方案2】:

如果您使用 Unrealm repo,必须删除对象并在写入事务中再次保存。

【讨论】:

以上是关于如何在 Realm Swift 中更新对象的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Realm Swift 中使用 NOT IN

如何在 Realm swift 中过滤为当前日期创建的事件?

Realm (Swift):如何在迁移期间获取 MutableSet 数据?

Realm Swift 使用部分更新 collectionView

什么时候/如何排序Realm孩子 Swift中UITableView的属性

升级 Swift Realm Braking Changes,我可以更改类名或如何解决冲突?