NSKeyedArchiver encode only part of an array - iphone

I have a list of objects that can sometimes change, and I want to keep a persistent cache on the device whenever the app is closed or move to the background.
Most of the objects in the list will not change, so i was wondering what is the best way to save the list. I have two major options i think about:
Using NSKeyedArchiver / unArchiver - This is the most convenient method, because the objects i'm serializing hold other custom objects, so this way i can just write a custom encode method for each of them. The major problem is that i didn't find on Google how to serialize only the changed objects, and serializing the entire list every time seems very wasteful.
Using SQLite - this is what i'm currently using, and the worst problem here is that adding \ changing properties of the objects is very complicated, and much less elegant.
Is there any way that i can enjoy the convenience of NSKeyedArchiver but only serialize the changed objects?

Like Adam Ko I would suggest using Core Data:
This kind of problem is what it's really good at, after all!
If your cache items are independent from each other, this could be achieved by simply wrapping your cache-items by a thin layer of NSManagedObject (i.e. you could benefit from Core Data with only minor changes to your app).
This wrapper entity could store an archived version of a cache item in an attribute of type NSBinaryDataAttributeType and provide access to the unarchived object through a transient property.
See Non-Standard Persistent Attributes for an example.

Related

Searching Core Data vs. Plist

I am searching 350 dictionary objects. Would it be more efficient to store the data in Core Data or a plist for searching?
Basically, each object is a dictionary with 8 key-values. The 350 objects are stored online in a JSON feed. I would like to download the feed when the app first launches, and then store the data into either core data or plist. In the app, there is a table with several object as default. A user is then able to add/delete these items. When a user clicks add, I want to display to the user all of the 350 objects, as well as provide a search mechanism.
In that case, should I store the JSON feed into a Plist or using Core Data?
It depends. If you aren't running into an actual performance issue, do whichever is more readable and appropriate for your application. For example, if you are saving data for which the user can add records of some sort, core data handles common situations for that and can be used with a fetched data controller to manage a table quite smoothly. It can also easily bind to your object model so you don't have to do key lookups.
If you have a reasonable amount of static data or editable values to a static list of keys and you always need to load all of it, go ahead and load a plist for convenience. Post more information about your specific situation and I can update my answer.
UPDATE:
I think you'll probably want to use Core Data for a few reasons. First, if each of these objects have the same 8 keys, you'll want to represent each one with a bound object instead of a dictionary. Second, Core Data is meant to be searched, sorted, and filtered. Third, with NSFetchedResultsController it isn't much harder to bind it to a table (with right indexes) or scroller selector. If you name the properties of your NSManagedObject the same as your 8 keys, it'll be pretty easy to load from JSON as well using KVC.
You could use a plist, but will have to do more leg-work.
As with many things in life, it depends. I would say a plist would probably be fine as long as the data is not too large to keep in memory. Also, if the data is static, I would lean toward plist. CoreData is better if you have a lot of data or a lot of related data objects and that data changes over time.
Based on your edits. I agree that Core Data is the way to go. Whenever you are adding/updating/deleting/sorting/searching/filtering data on a frequent basis, I prefer Core Data and that is Apple's recommended method as well.

how to store a custom config class in core data (i.e. key-value design or custom class)

Any advice on how to store a simple custom config class in core data. Options would be I think:
Entity with a "key" and "value" attributes - perhaps different attributes to represent different possible types (e.g. Integer16, String etc)
Custom class type entity which specific attributes for each config item I want - only catch would be that you would only ever want have one record in this entity, but the benefits would be it should be more usable I think: e.g. for the "fontSize" config items it would just be once you get the 1st record back from core data: "configRecord.fontSize". No need to access via a key-value arrangement and then cast the result or whatever.
Comments?
If there would only ever be one of these, I am not sure why you would save this information in Core Data and not simply as NSUserDefaults. Don't get me wrong, I like Core Data a lot. But seems like a lot of overhead for what could be stored as a dictionary.
If you had many of these, then Core Data and your second option would enable easy searching, etc. But this is not the case.
In terms of "configRecord.fontSize" convenience, you could read in NSUserDefaults into your own custom class and provide getters/setters there - without resorting to Core Data.
Just my two cents worth ;-)
I've run with my options 2 which seems to work a treat - and lieu of any suggested disadvantages (which I haven't found yet)

NSFetchedResultsController does anyone have any insights into the cache implementation?

this is a bit of an odd question, so I'll start at the beginning...
My needs for NSFetchedResultsController (NSFRC) are the ability to perform filtering and sorting after the objects have been fetched, mostly because the filtering and sorting require querying the fetched objects themselves, and is therefore not possible with NSFRC. So, I wrote my own class, BSFetchedResultsController, which aims to replicate the functionality of NSFRC (delegate notifications, automatic sectioning and caching) but with added hooks for the user to set their own blocks for filtering and sorting. The code for this class is on github here if anyone wants it: https://github.com/blindingskies/BSFetchedResultsController, although I wouldn't consider the class ready yet as a drop in replacement of NSFRC.
So, I've not yet implementing caching, mostly because I'm not really sure how Apple has implemented it. The caches are stored in binary files here:
{app dir}/Library/Caches/.CoreDataCaches/SectionInfoCaches/{cache name}/sectionInfo
So, presumably, my class would need to store its caches in a similar location? How is this structure organised/work? The cache needs to store the NSFetchPredicate (or properties required to re-generate it), and it needs to archive the fetched objects somehow. But, NSManagedObject doesn't conform to NSCoding, so, how does it archive the objects? And lastly during the NSNotificationCenterDidChangeNotification handler the cache needs to be updated.
So, the real aspect of this is how to archive the fetched objects, I'm leaning towards just saving the objectIDs in an array? And then just get those objects from the context. Is that enough?
If anyone has thought about how to implement
Okay, so to answer my own question, I've implemented the cache as follows:
Created another class which retains the entity (NSEntityDescription), fetch predicate (NSPredicate) and sort descriptors (NSArray) of the NSFetchPredicate, along with the sectionNameKeyPath and additional BSFetchedResultsController objects (post fetch predicate, filter, comparator). Make this class NSCoding compliant.
Then at the start of the performFetch: method, if there is a cache name, unarchive the object and see if the properties match the BSFRC, and if it does, then use the cache's section data.
Then add another notification handler, to NSManagedObjectContextDidSaveNotification to flush the objects to the cache.
A couple of points... I found that archiving the NSFetchRequest directly (which is NSCoding compliant) didn't work, and at the moment, am only checking the name of the NSEntityDescription.
Also, I don't cache the whole object graph, just the URIRepresentation of the NSManagedObject's NSManangedObjectIDs. Then, I respawn these URIs given the managed object context after validating the cache.
It seems to work, although I'm not sure how often I should flush the objects to the cache...

Create a Core Date Entity Instance But not want it to be stored(non-persistent)

Sometimes I need instantiate CoreDateEntity to store some infomations for temporarily using.
But I needn't it be stored into DB.
currently I created a similar class which have same structures as the CoreDateEntity does.
It works well but I have to do many datas transfer between Two models.
Is there any better way to handle this?
Thanks for all the replies. but you guys just give me half answer of this. consider about this, I need place some entity without MOC into current database pool, how could I do this? I already checked the documents of CoreData, seems I didn't find API to transfer one entity from MOC to another MOC(manage object context).
According to Apple docs you can initialize a managed object without context if you specify nil as context.
- (id)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)context
You can assign entities to different stores when you set up the data model. Have one store be the persistent store and the other an in-memory store. You can't form relationships across stores but it sounds like you don't need that.
To assign a configuration, hit the configuration tab (the one with the wrench icon) in the entity detail (where you give it its name, class and parent). When you create the persistent store, add the configuration name to the options dictionary.
Update:
I think you maybe overcomplicating things. It sounds like you have some managed objects that will be temporary and some that will persisted but sometimes you may want to save the temporary objects. I don't think you should bother trying to separate out the "temporary" objects. Doing so just adds complexity without any performance benefit. Instead, just use ordinary persisted objects and then delete the ones you don't want.
Always try the simplest solution first.
Use two different managed object context's and only save the objects from one context. Be careful not to set relationships between objects of two different context's - this doesn't work.

Key-Value Coding

I had a straight forward approach of turning Key/Value pairs of an XML excerpt into an NSDictionary when I started a simple iPhone application. The problem is, I need to turn those NSDictionary's instances that once populated my UITableView's into custom classes because they require behavior and additional complexity. The problem here is that now in order for me to instantiate an object and fill its instance variables with key/value pairs from a web service becomes that much more difficult. I can no longer throw it into a method that iterates through the XML and uses KVC to set its instance variables.
What kind of other solution is out there?
You can still use key value coding methods on your custom class, as long as you name your variables appropriately there's no difference there. With that being said though, when I'm working with XML I usually end up testing each node name or creating a key lookup table, since the names in the data source I'm working with aren't key value coding compliant. If you have control over the data source though, you could just continue to use setValue:forKey:.
I'd recommend reading this guide about key value coding if you haven't already. It's fundamental to many great tools in Cocoa.
Look into NSCoding. You can use the NSCoding protocol to save your object, properties and all, as data.
Once your object is NSCoding compliant, you can just archive the whole array of objects using NSKeyedArchiver.
Please note that if you have a large number of objects, this can dramatically affect the app's performance on the iPhone during load and save.