CoreData or Individual Files (iOS) - iphone

I've got a little conundrum: would it be better to use direct file management, or a CoreData SQLite database?
Here's my scenario:
I have a bunch of 'user' objects, each with a list of 'post' objects. This is easily done in CoreData, and would be great - however, the 'post' objects are downloaded from a web server, and they each have a unique identifier. I don't want to have multiple 'post' objects with the same ID. I could solve this by caching CoreData responses into an NSDictionary, however this would not apply well to the design pattern of an application. As far as I am aware, when adding a new 'post' to my CoreData NSManagedObjectContext, I would have to lookup the unique ID to check for its existence (fast), then add it if it does not exist (slow), and update the previous if it does (fast). This is effectively replacing it. How would you guys handle this?
I've been trying to think of alternatives for a few days now, but no matter which way I look at it, CoreData is going to be slower than my alternative:
A file architecture inside the Caches/ directory of an iOS application could solve the problem. Something like this:
Users/
{unique ID}.user
{unique ID}.user
Posts/
{unique ID}.post
{unique ID}.post
Then, when retrieving a post object or user object, I can check the files for the existence of the data, and cache the file contents in an NSDictionary. If the ID exists in the dictionary, retrieve it from there instead. Replacing previous 'user' and 'post' objects is as simple as overwriting the file and updating the cache.
My second alternative would clearly be faster - however, I would not be taking advantage of any efficiencies built into CoreData, and I would have to provide my own memory management scheme to clear my cached dictionaries when a memory warning occurs.
Is there is some way of 'uniquing' in CoreData? That would solve my problem. Something similar to using a primary key in an ordinary SQLite database.
I'll start doing tests to verify speeds of both methods, but I thought I'd post this up here before starting in case anyone has any better solutions.

This exact question comes up a lot.
You can check if a value exist in Core Data without reading in the entire object. Just set the fetch to fetch the specific property you want to test, the ID in this case, and then return the fetch as a dictionary. Provide a predicate that looks for one or more IDs and if the returned dictionary has values, you know you have existing objects.
It's very rare that you can end up with a custom system which is faster and more robust than Core Data. It's rarely worth even trying.
Remember as well that premature optimization is the root of all evil. All this work is predicated on the premise that the simplest Core Data implementation is to slow. Have you actually tested that it is to slow? If not, do so before you try more elaborate designs.

After testing, I've found that CoreData at least halves the amount of time taken. The test I was running was as follows: I added 1000 posts to an empty CoreData object graph; and then retrieved 100 of those objects for updating. The time taken to add the objects was 0.069s, and the time taken to retrieve the objects was 0.181s. I retrieved these values on a 3G iPad device. Using files, adding these objects took 10 times longer, and retrieving them took 4 times longer.
My recommendation: Stick to using CoreData!

Related

Mongo DB Collection Versioning

Are there any best practices or ways we can use to version a collection or objects in a collection in Mongo DB?
The requirement of versioning a collection is because, the objects in the collection maybe added with new attributes going forward but the already added objects (i.e. old objects) will not be having these attributes and the values for these new attributes. So on retrieval, we need to make sure, the code is not broken in de-serializing the different versions of the same object in the collection.
I can think of adding a version attribute to the objects explicitly, but are there any better built in alternatives in Mongo DB for handling this versioning of objects and/or collections.
Thanks,
Bathiya
I guess the best approach would be to update all objects in a batch process when you start using the new software on the server, since otherwise you’ll never know when an object will be updated and you’ll need to keep the old versions of those forever around.
Another thing what I’m doing so far, and it worked (so far), to have the policy to only allow adding new properties to the object. This way in worst case the DB won’t have all the data, but that is fine with all the json-serializers I know. But this means you aren’t allowed to delete or rename properties as well as modifying their type (from scalar value to object, array; from object to scalar, array; …).
Since usually I want to store additional information instead of less, this seems like a good solution without any real limitation for me.
If you need to change the type because scalar value isn’t enough, you can still create some code around which would transform it for every object which has the old value into the new one. And if a bulk update from your side is able to perform the changes I’d still do it but sometimes it needs user input.
For instance if you used to save passwords only as md5-hash it was a scalar value. But someone told you, they should be stored as sha512 with a salt together, now you need an object field for the password, you could call it password_sha512 where you store the salt and the hashed password.

How do i stop my app from accessing the database numerous times for each cell?

I have a UITableViewCell, which receives a pointer to an object in the database. That object has it's own objects on a one-to-one relationship. I want to know how I can access various bits of information from these objects without it accessing the database each time. Sort of along the same lines as 'am I able to load the data in one go so it's all ready to go, as part of the pointer, rather than something that needs to be loaded from the database'?
You can use NSCache to cache the data. Before going to DB, check if the data is in the cache. If it is not, read the DB and put the results in the cache; next time the access is going to be almost instantaneous.
You can also use Core Data to access the database: it caches results for you.
Andrew,
You can set your fetch request to not load your items as faults, i.e. make all the data available instead of cached in the row cache, by using -returnsObjectsAsFaults. Also, you can prefetch the properties in relationships by using -relationshipKeyPathsForPrefetching. IOW, you can make sure that you do fetch everything in "one go."
Andrew

How can I detect when a NSPersistentStore needs to be saved?

I have an iOS application where I use coreData to store my "documents". They all share a common NSManagedObjectContext, and I frequently save the context.
I would like to keep track of the last modification date for the various "documents" (where each one is a separate NSPersistentStore) and store the date on a particular unique "root" object that each store has.
I could try to keep the modification time stamp up to date while the document is being modified, but it would be cleaner and more robust if I could just find out which persistent stores need saving at the time I am saving the context.
I can't find any way to detect if a persistent store needs saving. I can query the NSManagedObjectContext to see which managed objects need saving, although I can't find an easy way to see which store an object belongs to.
It seems like this is not such a strange thing to do and core data has all of the information that I am looking for, but I am having trouble finding an easy way to get access to that data.
Does anyone know of an easy way?
If I can't find an easier way, I will simply loop over the deleted / modified / inserted objects from the context, and write special code for each entity type to determine the store that the object belongs to.
Thanks in advance for any help!
Ron
[[managedObject objectID] persistentStore] is the persistent store you're looking for (or possibly nil if the object has not been saved yet).
The documentation suggests that it's nil if you've assigned it to a store but haven't saved; I'm not sure that this is true (and I don't see anywhere else where this info might be saved). I'd check it behaviour on 3.x, 4.x, and 5.0 beta if you have access to it.

How to save / reload a custom array to a plist

I'm loading in data from an sqlite database, storing the values i load from there in the instance variables of a custom class, and then adding this class to a mutable array, which i'm then assigning to the instance variable of my view controller, for use in a tableview.
I would, though, like to save this array into a .plist file in the documents directory on the app's first run, so that i can retrieve the whole object from there on load, rather than pulling all 214 items from the database.
Is this approach a better option? if so, could someone please help provide me with some code that will allow me to save an array of my custom classes as a .plist file? I've come across a lot of sample code on the web, but none of it works correctly.
I'd like to:
Check for the existence of the my_data.plist file.
If it exists, read it in as the array.
If it doesn't, read the data from the sqlite db into an array.
save this data to a .plist so that it can be read in faster later.
Thanks guys, appreciate any help you can give me.
It will probably be faster to just get the values from your database on launch. There will almost definitely be more cost to parse a plist containing these values than to just get them all from the database, unless the query you have to use to get them from the database is really slow.
Note also that once you're saving these objects to a plist on disk, you're actually going to be hurting performance of your program because you'll be writing your objects to disk twice and reading them from disk twice. You'll also be introducing opportunities for discrepancies between the plist and the database in the event of a bug or a crash.
That said, the only way to prove this to yourself may be to implement and profile both options, and compare actual numbers. Check out #occulus's link, above, for instructions how to read and write a plist. To profile your app, try using Instruments
When I google for "nsarray writetofile custom object" (no quotes) and click on the first link in the results, I find a really useful page.
For the record, it's this:
http://www.cocoabuilder.com/archive/cocoa/240775-saving-nsarray-of-custom-objects.html

What is the most practical Solution to Data Management using SQLite on the iPhone?

I'm developing an iPhone application and am new to Objective-C as well as SQLite. That being said, I have been struggling w/ designing a practical data management solution that is worthy of existing. Any help would be greatly appreciated.
Here's the deal:
The majority of the data my application interacts with is stored in five tables in the local SQLite database. Each table has a corresponding Class which handles initialization, hydration, dehydration, deletion, etc. for each object/row in the corresponding table. Whenever the application loads, it populates five NSMutableArrays (one for each type of object). In addition to a Primary Key, each object instance always has an ID attribute available, regardless of hydration state. In most cases it is a UUID which I can then easily reference.
Before a few days ago, I would simply access the objects via these arrays by tracking down their UUID. I would then proceed to hydrate/dehydrate them as I needed. However, some of the objects I have also maintain their own arrays which reference other object's UUIDs. In the event that I must track down one of these "child" objects via it's UUID, it becomes a bit more difficult.
In order to avoid having to enumerate through one of the previously mentioned arrays to find a "parent" object's UUID, and then proceed to find the "child's" UUID, I added a DataController w/ a singleton instance to simplify the process.
I had hoped that the DataController could provide a single access point to the local database and make things easier, but I'm not so certain that is the case. Basically, what I did is create multiple NSMutableDicationaries. Whenever the DataController is initialized, it enumerates through each of the previously mentioned NSMutableArrays maintained in the Application Delegate and creates a key/value pair in the corresponding dictionary, using the given object as the value and it's UUID as the key.
The DataController then exposes procedures that allow a client to call in w/ a desired object's UUID to retrieve a reference to the actual object. Whenever their is a request for an object, the DataController automatically hydrates the object in question and then returns it. I did this because I wanted to take control of hydration out of the client's hands to prevent dehydrating an object being referenced multiple times.
I realize that in most cases I could just make a mutable copy of the object and then if necessary replace the original object down the road, but I wanted to avoid that scenario if at all possible. I therefore added an additional dictionary to monitor what objects are hydrated at any given time using the object's UUID as the key and a fluctuating count representing the number of hydrations w/out an offset dehydration. My goal w/ this approach was to have the DataController automatically dehydrate any object once it's "hydration retainment count" hit zero, but this could easily lead to significant memory leaks as it currently relies on the caller to later call a procedure that decreases the hydration retainment count of the object. There are obviously many cases when this is just not obvious or maybe not even easily accomplished, and if only one calling object fails to do so properly I encounter the exact opposite scenario I was trying to prevent in the first place. Ironic, huh?
Anyway, I'm thinking that if I proceed w/ this approach that it will just end badly. I'm tempted to go back to the original plan but doing so makes me want to cringe and I'm sure there is a more elegant solution floating around out there. As I said before, any advice would be greatly appreciated. Thanks in advance.
I'd also be aware (as I'm sure you are) that CoreData is just around the corner, and make sure you make the right choice for the future.
Have you considered implementing this via the NSCoder interface? Not sure that it wouldn't be more trouble than it's worth, but if what you want is to extract all the data out into an in-memory object graph, and save it back later, that might be appropriate. If you're actually using SQL queries to limit the amount of in-memory data, then obviously, this wouldn't be the way to do it.
I decided to go w/ Core Data after all.