RealmDB is magically linked with objects it adds, reads. But that overhead is not always needed.
I can manually read all fields and assign them to new object but what is canonical way to get data unbinded from RealmDB?
Related
This question is poorly phased but this can be better explained in code.
We have a Core Data Stack with private and main contexts as defined by Marcus Zarra here: http://martiancraft.com/blog/2015/03/core-data-stack/
We call a separate class to do a fetch request (main context) and return an array of NSManagedObjects:
NSArray *ourManagedObjects = [[Client sharedClient].coreDataManager fetchArrayForClass:[OurObject class] sortKey:#"name" ascending:YES];
We then do some processing and store a reference:
self.ourObjects = processedManagedObjects
Our view contains a UITableView and this data is used to populate it and that works just fine.
We change the data on our CMS, pull to refresh on the UITableView to trigger a sync (private context) and then call this same function to retrieve the updated data. However, the fetch request returns the exact same data as before even though when I check the sqlite db directly it contains the new data. To get the new values to display I have to reload the app.
I have discovered that if I don't assign the processedManagedObjects to self, the fetch request does indeed return the correct data, so it looks like holding a reference to the NSManagedObject stops it from getting new data from the main context. However I have no idea why that would be.
To clarify, we're pretty sure there's nothing wrong with our Core Data Stack, even when these managed objects are not being updated, other are being updated just fine, it's only this one where we store a local reference.
It sounds like what's going on is:
Managed objects don't automatically update themselves to reflect the latest data in the persistent store when changes are made via a different managed object context.
As a result, if you keep a reference to the objects, they keep whatever data they already had.
On the other hand if you don't keep a reference but instead re-fetch them, you get the new data because there was no managed object hanging around with its old data.
You have a few options:
You could keep the reference and have your context refresh the managed objects, using either the refresh(_, mergeChanges:) method or refreshAllObjects().
If it makes sense for your app, use an NSFetchedResultsController and use its delegate methods to be notified of changes.
Don't keep the reference.
The first is probably best-- refreshAllObjects() is probably what you want. Other options might be better based on other details of your app.
Try setting the shouldRefreshRefetchedObjects property of the fetch request to true. According to the documentation:
By default when you fetch objects, they maintain their current property values, even if the values in the persistent store have changed. Invoking this method with the parameter true means that when the fetch is executed, the property values of fetched objects are updated with the current values in the persistent store.
I wish to save a dictionary containing some Core Data objects (bunch of different entities). The objects also have quite a few relationships (and inverse relationships) defined. What would be the best way to go about it?
I tried using NSKeyedArchiver and writing to a file. While that works great, when trying to read from the file using NSKeyedUnarchiver, it fails on one of the classes with the error
-[SomeEntity initWithCoder:]: unrecognized selector sent to instance
EDIT - More details
I have a bunch of objects, each having properties based on which they can be filtered. The properties are in themselves Core Data entity objects since they have a complex structure.
I wish to save the filters the user has selected so that the next time they view the objects, the objects can be filtered as per their previous selection.
Say there are 3 filters, Filter A, B and C and each can have 5 different values. Now the user might select Filter A1, A2, B1 and C3 (or a different combination). My question, how do I save these selected filters (A1, A2, B1 and C3 in this case) using Core Data?
Let me see if I understand your question: You have a collection of managedObjects that are already saved in a context. They may already be persisted in the SQL database. You want to save that collection ALSO to another file for other purposes. You have already considered saving the information of this collection inside core-data in some way and have already rejected it. You have also considered simply saving the query generation tokens to save the state of the database as it currently is, but that also is not what you want. The point is to have a file that contains a copy of some of the managedObjects organized in a way that you can get the data back without using the SQL database that was already designed exactly for that purpose.
Solution 1: Turn each managed object in a dictionary.
You can get every attribute and every property of every object by getting a managed object's entity and then accessing the attributesByName and
relationshipsByName property of the entity. From there you make a simple loop to put each property into a dictionary. I also suggest you store the objectID and point to the objectID when encoding the relationships. Then replace the managedObject in your dictionary with dictionary that contains all the attributes and relationship. This new dictionary should be easy to archive and unarchive.
This make sure that the data when you unarchive is exactly how you left it. When you unarchive you will get a COPY of data and if the managed objects have changed in your database since then, you will get the OLD values. Also these copies are not core-data object because they are unconnected to a managed Object Context.
Solution 2: Just save the Managed Object's ObjectId.
Replace every managed object in your collection with the object's objectId. This dictionary can be easily archived. When you unarchive it replace every objectId with a core data object (if found) using existingObjectWithID: on the context. If entities have been deleted then you won't get them back. If entities have changed then you will get the NEW values.
Solution 3: Don't do any of this
It seems to me that you may not be aware core-data are already saved in a database. If you have some collection of managedObjects, you should be able to recreated it from your database. If you aren't able to, then you should add properties and/or relationships that will allow you to so.
Try like this :
ARCHIVE :
NSDictionary *yourDictData = [NSDictionary dictionaryWithObject:json forKey:#"key"]; // This is for example. Here you have to replace ur dictionary
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:yourDictData];
UNARCHIVE :
NSDictionary *myData = [NSKeyedUnarchiver unarchiveObjectWithData:yourDictData];
I just start thinking about implementing Realm and have some newbie doubts.
For example I receive a list of objects which I transform into realm objects. How can I write the whole list directly to Realm, without writing each object separately?
A typical workaround comes into my mind, which would be defining a bigger object which contains this list as a property and writing that bigger object to the DB. But is it possible to write directly the obtained list of objects to DB without something that encapsulates them?
And also when preparing this list of Realm objects, I basically have a list of dictionaries. What's the best approach into transforming all of them directly into a list of Realm objects?
Just to confirm. When you mention your list of objects at the top and then mention that you have a list of dictionaries, are they the same thing?
If they are, and your data is coming down as a set of dictionaries, as long as the key names match the properties in your Realm Object models, then you can simply loop through each dictionary and pass each one to Realm to create it as a new entry in the database:
let realm = try! Realm()
try! realm.write {
for dictionary in dictionaries {
realm.create(MyObject.self, value: dictionary, update: false)
}
}
More information on that API can be found on Realm Swift's documentation page.
If your objects don't map directly to the properties in your Realm file, then you're going to need to manually reformat the structure of your list of objects until either could be inserted as a dictionary, or you can manually create your own Realm Object instances off them.
Based on some limited testing, I see that if I
Execute a Fetch request with result type = NSDictionaryResultType
Do some manipulations on the returned values
Store back the MOC on which Fetch request was executed
the changes in step 2 are not written back to the persistent store because I am changing a dictionary and not a "managed object". Is that a correct understanding?
Most likely you are abusing the dictionary result type. Unlike in conventional database programming, you are not wasting valuable memory resources when fetching the entire objects rather than just one selected attributes, due to an under-the-hood mechanism called "faulting".
Try fetching with managed object result type (default) and you can very easily manipulate your objects and save them back to Core Data. You would not need to do an additional fetch just to get the object you want to change.
Consider dictionaries only in special situations with huge data volumes, difficult relational grouping logic, etc., which make it absolutely necessary.
(That being said, it is unlikely that it is ever absolutely necessary. I have yet to encounter a case where the necessity of dictionaries for fetches was not an indirect result of flawed data model design.)
Yes, kind of, you can't store a dictionary back into the context directly so you can't save any updates that way.
If you get a dictionary object then you need to include in it the associated managed object id (if it isn't aggregated) or do another fetch to get the object(s) to update.
I am mapping data using RestKit 0.20 into a Core Data and displaying it in a UITable. I am writing the data, an 'Activity' object, to the mainQueue's ManagedObjectContext and it all works fine. Now I need a second table with Future-Activities and also a third table with Past-Activities. I need a ManagedObjectContext for each table as the sorting is done on the server side. How can I handle this and have persistent data. Is 'newChildManagedObjectContextWithConcurrencyType' what I need to use?
Keep a single store. Use a predicate to filter out the items you want.
If you can download all of the data (and you're happy to do that even though some of it may not be used by the user), and you can tag them for what they are used for then that is an option.
From a RestKit point of view, you can use metadata to tag the items during the mapping process so that you know how they should be used (and then filter on that). This requires that you add a new key to the item - but, if one item could be in all responses this will be problematic because the values would get overwritten.
To use metadata, simply add a new mapping like:
#"#metadata.URL": #"requestURL"
Where #metadata.URL is the URL used to make the request and requestURL is the property on your entity that you can use for filtering. The predicate will check for contains your types ("all_day" "start_time" "end_time").