Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update an object in Realm Swift

I'm trying to learn how to use Realm Swift and Charts so I can eventually use them both in an app I'm building and I'm having a hell of a time figuring out Realm. Eventually, I'm planning on having Charts look at my Realm DB and then display the charts based on the data, but before I do that I have a need to check to see if a realm object exists yet, if it does not, to create it and then as the user uses the app add 'counts' to that record and update the chart accordingly.

As I'm learning I've broken this down into steps. I've already figured out how to check to see if a record exists and if not to build it like this:

My Realm Model:

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)         }     } 

I've verified that his work via the Realm Browser app.

Next on my To-Do list is to figure out how to update a record for "today's date's record". To do this I've created a button so when tapped it would attempt to do this. I've been googling and googling and have come to think that since I don't use a primary-key in my Model, I have to first delete the specific record in question and then add it again with the new data. I can't for the life of me figure out how to do this based on the Realm documentation and even more googling. This is what I've got, though it does not work:

@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")         }     } 

When I tap the btnUpdate1MW button I get the following error in Xcode:

Terminating app due to uncaught exception 'Invalid value', reason: 'Expected object of type date for property 'date' on object of type 'WorkoutsCount', but received: 2017-04-24 07:00:00 +0000'

like image 599
jammyman34 Avatar asked Apr 25 '17 23:04

jammyman34


People also ask

Does realm work with SwiftUI?

Realm objects have bindings to SwiftUI controls and, much like toggling the bought property, they already start a realm transaction to write the changes in the database whenever you change those values.

How do you delete a realm object?

To delete all objects from the realm, call Realm. deleteAll() inside of a write transaction. This clears the realm of all object instances but does not affect the realm's schema.


1 Answers

Updating objects is just assign a value to a property within a write transaction. See our documentation.

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

So you don't need to delete and then add an object. Just assign new value to the property in write transaction like the following.

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     } } 

FYI: Please don't use string interpolation in a query. Generally constructing an important string by string interpolation is bad practice. Use NSPredicate's string substitute syntax like filter("date = %@", removeTodaysItem).

like image 139
kishikawa katsumi Avatar answered Sep 21 '22 15:09

kishikawa katsumi