How to save / reload a custom array to a plist - iphone

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

Related

How to maintain the huge result of xml parsing

I am developing one application. In it I get 1000 results from xml parsing. Every result has different attributes. So I create one class for the attributes and create one object for every result. I save the results in one array. My doubt is due to the fact that this is a lot of results and I may face memory problems. If this is a problem, how do I handle that? Please tell me how to do this.
If you're parsing an exceptionally large document, use NSXMLParser and a delegate object to parse the document. Rather than creating an enormous tree of objects to represent the XML, the parser will call your delegate each time it encounters a new attribute, element, etc. This way you can build up your data objects directly, without wasting memory on an intermediate XML parse tree representation.
Once you are doing this, you can save the objects as you create them, or in batches.
If you're very memory conscious, you can actually use NSXMLParser to parse the input stream as it is downloading, so you never even need to have the full XML text in memory. (To avoid interruptions you could also download to a disk file, then parse from the file.)
Memory management in Objective-C is very well explained in below discussion..
http://www.iphonedevsdk.com/forum/iphone-sdk-tutorials/7295-getters-setters-properties-newbie.html
hope this will answer your question...

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.

CoreData or Individual Files (iOS)

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!

Property Lists: How to use it to provide easy exchangeable default data to the user?

I want to ship some default data with my app. This data can be stored perfectly in a property list. The strucure is simple:
Root
0
animalType = cat
animalName = Tom
1
animalType = dog
animalName = Rambo
I thought: When I use a property list rather than hard-coding it somewhere, then I could easily provide more defaults to choose from after the app is distributed already. If I would hard-code it, I would have to provide heavy upgrades every time, and Apple would take weeks to let them pass.
But there's one thing I don't get. I make that property list manually in Xcode and put that in my Resources group. As far as I know, Xcode would compile it into some binary format. In my app I would use NSPropertyListSerialization to create a NSDictionary out of it. But this property list would not get placed into the documents directory of the sandbox, right? So if the application would download an update of that property list some time in the future, the update would have to go into documents dir, but the app would still look at the old plist in the root, right? Where to put it? Must I copy it to documents, just like an sqlite database?
And the other thing: When I edit the plist and provide the whole thing as an XML for download/update from a server, then of course that thing would not be "compiled" into some binary format. How would that work? Would NSPropertyListSerialization have trouble reading it? Must I compile that thing every time with XCode and let the app download some binary stuff?
There are two commonly used property list formats: proprientary binary format and xml format (DTD). You can use either of them, and NSPropertyListSerialization will detect automatically, which one is used for your data when de-seralizing.
XML format is more verbose, but it's simple to generate. If you're publishing data from server, you might consider generating xml plist, and compress it with gzip or something.
Now to your first question about where to store the data. To make application payload smaller you might first check documents directory for updated plist, and if it is not present - load default plist from your application bundle.
One general approach used is to always copy plists or other updated elements into the application documents directory - then you just always load from there, and replace when there is an update.
Or you could pre-load the data into a database, download plist updates and refresh the database entries at that time.

Help with dictionaries, arrays and plists on iPhone

I would appreciate some help with something I working on and have not done before now and having some proplems because I don't think I understand exactly how to do this. What I'm wanting to do i'm sure is simple to most all of you and will be to me as soon as I do it the first time correctly....anyway.... I have a tableview that I'm needing to populate with two things, a username and a number with a count of items (the username could be a primary key). Currently I have a tableview populating and editable with an array....no problem....I know how to do that.
The two parts I need help with understanding is to:
read a plist with these two values into a dictionary, and read them into two different arrays that I can use with my tables.
Save the arrays back to the dictionary and then back to a plist.
I think I'm getting the most confused with how to store these two things in dictonary keys and values. I've looked that over but just not "getting it".
I would appreciate some short code examples of how to do this or a better way to accomplish the same thing.
As always, thanks for your awesome help....
You can use NSArray method writeToFile: atomically: to dump your data into a file, you can then use initWithContentOfFile to retrieve the information from t hat file just as you dumped it previosly. I believe if you have dictionaries in your array you should be able to get them back this way. You can always use core data as well for storage if you find your structures to store are getting complex and dumping the in a file and getting them back to recreate some o bjects is becoming messy.
The approach that would perhaps be the simplest is to store the data as an array of dictionaries. This has the issue that recreating the array from a plist with mutable leaves is convoluted at best.
But if you can tolerate the performance hit of replacing dictionaries when updating the list instead of modifying them, it might definitely be the simplest course of action.
This also has the added benefit that your datasource only needs to deal with one array, and that the whole shebang would be Key-Value Compliant, which might further simplify your code.