How can I add or update a Realm object in Swift? - swift

I have a Realm object that may or may not have been added to Realm yet, and I want to update a property (while adding it if it hasn't been added yet).
Here's how I'm doing this right now:
try! realm.write {
if cat.realm == nil {
realm.add(cat)
}
cat.name = "Photon"
}
Is checking if the object has a realm attached to it the correct way to determine if it's been added or not?

Yes. Checking Object.realm == nil is the best way to see if an object has already been inserted into a Realm or not yet. :)

Related

Realm updates are not saving

So I'm trying to update a List property of an Object class in Realm. The property of the Object updates, but for some reason when it gets to the Realm, the update never occurs. In other words, I've confirmed that the changes have been made to the actual object just after I made the changes(the List updates in the object), but after I add to the realm, and then get the object back from the realm, it's as if nothing ever changed. Here is the code:
do{
try! realm.write{
let course = realm.objects(Course.self).filter("id =='\(courseID!)'").first
course!.days = List<String>()
for day in daysSelected{
course?.days.append(day)
}
realm.add(course!, update: .modified)
}
}catch{
print(error)
}
Also, you should know that when I update other properties like Strings, the changes go through just fine. Am I doing something wrong with lists? In my object class, the list is declared as:
var days: List<String> = List<String>()
According to the documentation:
Properties of List type defined on Object subclasses must be declared
as let and cannot be dynamic.
Rather than defining your list as:
var days: List<String> = List<String>()
Define it as:
let days = List<String>()

Swift UITableView Realm wrong order after delete

I have a database in Realm which i display in a UITableView which works perfectly. I added a delete functionality which lokks like below.
if let item = items?[indexPath.row] {
do {
try realm.write {
realm.delete(item)
}
} catch {
print("Error deleting item, \(error)")
}
tableView.reloadData()
}
Let's say I have some data in the database like 1,2,3,4,5. When I delete the '2' I want it to be like 1,3,4,5 but it is 1,5,3,4. So the last entry respectively the entry which is displayed at the bottom will always replace the deleted data. How can I fix it?
Objects is Realm are stored as unordered if you want them in order then you have to apply below code or store it as a List.
let result = realm.objects(ModelClass).sorted("attribute", ascending: true)
ModelClass is the name of your Realm Object Class
Attribute is
Object property on the base of which you want them.
Hope it will help you.

Retrieving NSOrderedSet from Core Data and casting it to entity managedObjectSubclasss

Im making a Fitness app to learn Core data, and I have found that I need to let the user store every performed workout as a WorkoutLog item, and in there, there should be a series of ExerciseLogs which represents performances of that exercise (it contains each lift and also a reference to the actual exercise design).
Problem is that after a while i realize that i need to have these ordered, so that the next time i want to show the user their workout, the order that the exercisese were performed should be the same.
So I checked "ordered" in the top right of the image there, and now my code is in dire need of an update. I have tried to read as much as I could about working with NSOrderedSet and how to fetch them from core data and then manipulate them, but I havent really found much of use to me. (I have no experice in objective-c)
For example my code that used to be:
static func deleteWorkoutLog(_ workoutLogToDelete: WorkoutLog) {
guard let exerciseLogsToDelete = workoutLogToDelete.loggedExercises as? Set<ExerciseLog> else {
print("error unwrapping logged exercises in deleteWorkoutLog")
return
}
I get the error: .../DatabaseFacade.swift:84:77: Cast from 'NSOrderedSet?' to unrelated type 'Set' always fails
So what ive learned about sets and core data no longer seems applicable.
Im far from an expert in programming, but im very eager to learn how to get access to the loggedExercises instances.
TLDR; Is there a way to cast NSOrderedSet to something I can work with? How do we usually work with NSManagedSets from core data? Do we cast them to Arrays or MutableSets? I would very much appreciate an example or two on how to get started with retrieving and using these ordered sets!
Thanks
For anyone else wondering how to get started with orderedSets in core data:
After setting my the WorkoutLog.loggedExercises "to-many" relationship to be ordered, I managed to access them through the mutableOrderedSetValue function like this:
static func deleteWorkoutLog(_ workoutLogToDelete: WorkoutLog) {
let orderedExerciseLogs: NSMutableOrderedSet = workoutLogToDelete.mutableOrderedSetValue(forKey: "loggedExercises")
let exerciseLogsToDelete = orderedExerciseLogs.array
for exerciseLog in exerciseLogsToDelete {
guard let exerciseLog = exerciseLog as? ExerciseLog else {
return
}
Works great so far.
And to rearrange the NSOrderedSet I ended up doing something like this:
// Swap the order of the orderedSet
if let orderedExerciseLogs: NSOrderedSet = dataSourceWorkoutLog.loggedExercises {
var exerciseLogsAsArray = orderedExerciseLogs.array as! [ExerciseLog]
let temp = exerciseLogsAsArray[indexA]
exerciseLogsAsArray[indexA] = exerciseLogsAsArray[indexB]
exerciseLogsAsArray[indexB] = temp
let exerciseLogsAsOrderedeSet = NSOrderedSet(array: exerciseLogsAsArray)
dataSourceWorkoutLog.loggedExercises = exerciseLogsAsOrderedeSet
}

Object has been deleted or invalidated. (Realm)

Please refer Error: Object has been deleted or invalidated. (Realm)
I encounter this error with both 2 cases also.
I try to find the DBProduct before delete, but it also got Error: Object has been deleted or invalidated. Is this wrong? Please help me. I call this method in block of Alert view as Case 2.
let realm = try! Realm()
try! realm.write {
let dbProduct = realm.objectForPrimaryKey(DBProduct.self, key: product.id)
if dbProduct != nil {
realm.delete(dbProduct!)
}
}
Update: This issue happens on iOS8 only, and it is OK on iOS 9.
Normally, that error should only be thrown if you try and access a property of a Realm object that has been deleted, or if you explicitly told its parent Realm object to invalidate.
Like James said, it's quite likely that your product variable there has already been invalidated, in which case trying to call product.id would likely cause that crash.
If that's the case, then the easiest thing to do to fix this would be to avoid using the product variable and instead, simply making a copy of the value of id directly. This way, if the object is deleted/invalidated, you still have its primary key in which you can test to see if it still exists.
On a side note, this code could certainly be made a bit more efficient as well. It's not necessary to perform queries inside write transactions and you should only open a write transaction if there actually was an object to delete (Write transactions are pretty heavy things, so they should be avoided as much as possible).
let productID = product.id //save a copy of the ID in case 'product' gets deleted.
let realm = try! Realm()
let dbProduct = realm.objectForPrimaryKey(DBProduct.self, key: productID)
if dbProduct != nil {
try! realm.write {
realm.delete(dbProduct!)
}
}
I hope that helped!

Delete all data from specific Realm Object Swift

Before i get too far into my question. My goal, which may influence your answers, is to remove Object data if it is no longer in the cloud.
So if I have an array ["one", "two", "three"]
Then in my server I remove "two"
I want my realm to update the change.
I figure the best way to do this is to delete all data in the specific Object, then call my REST API to download the new data. If there is a better way, please let me know.
Okay so here is my problem.
I have an Object Notifications()
every time my REST API is called, before it downloads anything I am running this:
let realm = Realm()
let notifications = Notifications()
realm.beginWrite()
realm.delete(notifications)
realm.commitWrite()
I get this error after running: Can only delete an object from the Realm it belongs to.
so i tried something like this:
for notification in notifications {
realm.delete(notification)
}
realm.commitWrite()
The error I get within xcode is this: "Type Notifications does not conform to protocol 'SequenceType'
Not really sure where to go from here.
Just trying to figure out realm. Completely new to it
Note: realm.deleteAll() works, but I don't want all of my realm deleted, just certain Objects
You're looking for this:
let realm = Realm()
let deletedValue = "two"
realm.write {
let deletedNotifications = realm.objects(Notifications).filter("value == %#", deletedValue)
realm.delete(deletedNotifications)
}
or perhaps this:
let realm = Realm()
let serverValues = ["one", "three"]
realm.write {
realm.delete(realm.objects(Notifications)) // deletes all 'Notifications' objects from the realm
for value in serverValues {
let notification = Notifications()
notification.value = value
realm.add(notification)
}
}
Although ideally, you'd be setting a primary key on Notifications so that you can simply update those existing objects rather than taking the extreme approach of nuking all your local objects simply to recreate them all (or almost).