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'
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.
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.
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)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With