Delete all data from specific Realm Object Swift - 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).

Related

SwiftUI Query Realm Database

In my Realm DB for ChatMessage I have the following data object:
When i follow the tutorial on retrieving data/query : https://www.mongodb.com/docs/realm/sdk/swift/crud/read/
let realm = try! Realm()
let specificPerson = realm.object(ofType: ChatMessage.self,
forPrimaryKey: ObjectId("6369ee9db15ac444f96eb5d6"))
print(specificPerson!.author as String)
I receive fatal error Nil, it cannot find anything. from the line
print(specificPerson!.author as String)
LiveChat/ChatView.swift:59: Fatal error: Unexpectedly found nil while unwrapping an Optional value
When I do a broader query for all,
let chatM = realm.objects(ChatMessage.self)
print(chatM)
print(type(of: chatM))
I receive empty object
Results<ChatMessage> <0x7fe4d163efa0> (
)
Results<ChatMessage>
I am adding the Chat messages Via
#ObservedResults(ChatMessage.self,
sortDescriptor: SortDescriptor(keyPath: "timeStamp", ascending: true)) var messages
private func addMessage(){
let message = ChatMessage(room: room, author: userName, text: messageText)
$messages.append(message)
messageText = ""
}
Similar to https://github.com/mongodb-developer/LiveTutorialChat/blob/main/iOS/LiveChat/LiveChat/Views/ChatsView.swift
Regarding your updated code:
So yes, you are indeed creating the objects (using the .append(_:) method on an #ObservedResults collection) in a correct way. This means that you are likely opening the wrong realm database when you're querying for the objects. Please have a look at Realm's documentation regarding realm configuration, specifically on how to set the default configuration. Calling try! Realm() without any parameters will use this default configuration to open the database.
Original reply
If let chatM = realm.objects(ChatMessage.self) returns an empty Results object, the realm you're querying does not contain any objects of the ChatMessage type. It's as simple as that. Logically, let specificPerson = realm.object(ofType: ChatMessage.self, forPrimaryKey: ObjectId("6369ee9db15ac444f96eb5d6")) would then also return nil.
Without seeing how and where you're creating the missing ChatMessage objects, it's hard to say what's going wrong. Some common missteps:
You are querying the wrong realm database: If you are only every accessing realm through let realm = try! Realm() this shouldn't be a problem.
You haven't actually added any ChatMessage object to the realm database: Simply initializing an object is not enough, You need to explicitly add objects to the Realm database using either Realm.create() or Realm.add():
let realm = try! Realm()
let exampleObject = ChatMessage()
print(realm.objects(ChatMessage.self).count) // Prints "0"
// Add to the realm using either create() or add()
realm.add(exampleObject)
print(realm.objects(ChatMessage.self).count) // Prints "1"

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

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
}

Realm write fails on second time being called

I have a service for retrieving data from an api, it returns json that I map and then populate to Realm and finally display this to the view.
I have way for a user to force refresh the retrieval of data, which means I need to update my Realm data aswell. This works fine on the first time I call the method. But if I try to do it again it crashes every single time with this exception.
*** Terminating app due to uncaught exception 'RLMException', reason: 'Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first.'
This is how my function works:
private func writeCollection(someKey: String?) {
let realm = try! Realm()
try! realm.write {
realm.add(someObject[someKey!]!, update: true)
}
}
This error occurred inside a different function then initially thought. I was holding a dictionary like this [someKey:someObject] and using this dictionary as a reference to write from.
Problem was this was outside the try! realm.write
// removed this reference
// var dictionary = [String:SomeObject]()
realm.write {
let someObject = SomeObject()
someObject.id = someKey
realm.add(someObject, update: true)
}

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!