I am building a very simple app to store data on people like name, age, etc. I give the user the option of changing the data such as when a person has a birthday. I can't figure out the best way to store the data.
I have searched for a long time now and I can't find the simple answer that I am looking for. If I change the data in a mutable array will that data be changed permanently? I mean will that write over the existing code and change the data so that it will still exist when the app is closed and reloaded again?
So far I am not able to do that. I have experience in MySql and Sql server so I have a tendency to go that direction if possible, but I would really like to use a mutable array or mutable dictionary if possible. This may be such an elementary question, but I can't find an answer anywhere.
You have some misconceptions.
The objects you create are in memory. There's nothing permanent about them. You have to save them somehow or they are gone when you quit the application and come back.
If you want to save an array, you have a number of options.
If the array contains nothing but objects of type NSString, NSData, NSDate, NSNumber, NSArray, or NSDictionary, you can save the array using the system class NSUserDefaults.
NSArray also has a method writeToFile:atomically: that will save an array of data to a file.
If your array contains any objects other than the types I listed above, though, neither of those approaches (NSUserDefaults or writeToFile:atomically) won't work.
The other option is to use an NSKeyedArchiver to convert the contents of your array to data, and then write that data to a file. In order for that approach to work, every single object i your array, and all the objects in those objects, need to support the NSCoding protocol.
As others have pointed out, you could also use Core Data or mySQL to save your data, but that seems like overkill for just saving an array.
Take a look at Core Data. It is the easiest way to manage this kind of data storage requirement on iOS.
Take a look at my book, it got good reviews and is perfect for what you are trying to do: http://www.amazon.com/Pro-Core-Data-iOS-Professionals/dp/1430233559
If you want an easy way to get started, there are tons of online tutorials too. For example Ray has written some good stuff:
http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started
Mutable means you can change the data at any time, so no, it's not permanent.
Yes, it will be permanent in terms of what you are asking. Although because the array is mutable it means you can always change the data back, the initial data will be overwritten by this new data.
Edit: No, the information will not remain after closing the app. You will need to programmatically save it. I would use Core Data.
CoreData is the way data is normally persisted in Cocoa and Cocoa-Touch. It also gives you some nice extras like undo support. But it has a big learning curve.
If what you're doing is super-simple, look at NSUserDefaults. If you need a little more flexibility, you could always use NSArray's -writeToFile:atomically: and -initWithContentsOfFile: (there are also versions of both those methods that take URLs instead of file paths).
Anything more complicated than that, and it's probably worth the trouble learning CoreData.
Related
I've got a bunch of managed objects that i'm fetching from a managed object context. These object have a imageFilePath attribute, which is just a path to an image data object ive saved to a directory on the phone. My question is this - what is the best way to batch convert all these data objects into an array of photos?
I'm considering just iterating thru the array of the managed objects, but that seems somewhat inefficient. I could also perhaps create a separate entity from this attribute in my model, and grab them directly.
Is there a way i could apply a block to each result of my fetch as it comes in?
thanks!
If you're worried about the Core Data side of things, take a look at the fetchBatchSize you can set on NSFetchRequest. You'll have to experiment a bit to see what size will work best for you, but something like 25 is a good starting point. That way Core Data will not fetch all objects from disk at once, but fault them in 25 at a time. You still see a normal NSArray and Core Data does all the magic in the background.
The copy method only makes a shallow copy, i.e. a new copy of the collection itself, not all the objects storing inside. The book I am studying now suggested to use archive to create deep copy, i.e. use NSKeyedArchiver to save the collection object to an NSData object, then load it back to another collection object using NSKeyedUnarchiver. This method works, but I am not sure how efficient it is to cope with large collection objects. Is there any other deep copying method which might works better?
Alright, this is what I want to know:
Any method which involves less coding?
Any method which is more CPU efficient?
Any method which can achieve both? :P
What #dasblinkenlight said...
NSKeyedArchiver is designed especially for large object graphs. It is of course possible to build something more efficient if you have highly specialized knowledge of your object graph, but that would almost always be a mistake unless you have a very special problem.
Your book is correct. Use archivers to create deep copies.
I am not sure of the numbers, but the NSKeyedArchiver route is not going to be very computationally expensive. It looks like the long way round, but really is not much more inefficient than something custom made (like #Rob Napier said). It is, however a lot more reusable.
When still in doubt, an interesting experiment may be a deep copy of a large but simple data set, and time that against something custom made.
need to save some persistent data. the data would only contain 3 or 4 arrays with 100-200 single value entries.
(array) data
(
(
(dictionary) key -> value
)
(
(dictionary) key -> value
(
//etc
)
these are just simple lists to show in pickers.
so far i've used NSUserDefault to store single dictionary values, and i'm wondering if it would suffice for this new data or do i need to consider using Core Data?
at this point in time, i don't see my program needing to sore more data then this.
NSUserDefaults shouldn't have any trouble with the data usage you described.
That said, it doesn't mean it's the ideal solution. NSUserDefaults are really intended to deal with user preferences. So, if these values aren't preferences NSUSerDefaults isn't really the place for them. (not that it won't work)
CoreData might be a little overkill for your situation, but it might be worth the intial learning curve to have that skill under your belt.
Another solution would be to simply use NSArray or NSDictionary classes if your data is consistant.
NSUserDefault doc - http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
Really depends on task.
You should answer on these questions:
How often this data should be changed?
How often this data should be queried ?
What kind of queries do you want to use on this data?
As far as I see, if you just need to show them in pickers, you obviously can use NSUserDefaults, or plist file to save this data between launches.
And NSArray/NSDictionary to use it in app.
How often is this accessed or changed? I would guess that NSUserDefaults is fine.
I'm trying to create an application that stores profile information..
Name: first Last
Email:
Department:
Title:
What would be the best approach?...
I was thinking of using an NSDictionary for the info.
But I'm unclear on how to combine all the attributes of the profile, into the NSDictionary...
Would I create an NSDictionary for NAMES, then another for EMAILS, ect...?
Any insight is greatly appreciated, Thanks
This is directed at those who suggest a struct: I'm sorry but why even bother using Objective-C if you're not going to use Objective-C? I'm not sure where this "use a struct" trend is coming from but it's absurd when considering primary, first-class app objects that are to be heavily manipulated with the Cocoa API.
To the OP: Use an Objective-C class and be done with it.
An NSDictionary is great as an indistinct container or map and, provided everything in it is compliant, the whole thing (container and contents) can be archived and unarchived with one line of code.
In your case, you already know a predefined set of attributes (and maybe even methods) of this object you want to describe (a Profile), so create an Objective-C class and make it NSCoding compliant so you can stash it in any standard Cocoa container and have it easily archived/unarchived, etc. You can also take advantage of automagic behavior such as having a -fullName property that returns a concatenation of the first and last names while participating rather effortlessly in Key Value Observing, using NSPredicate filters, sorting by key etc. You can also implement -copyWithZone: so a Profile instance is easily copyable, etc.
"Why use a hammer on that nail? It's wasteful. Plenty of perfectly good sticks out there you can put rocks on."
Please ... just use a class. It makes functionality so much simpler to add in the long run.
I know there is a NSUserDefaults object. I haven't worked with it.
There is a tutorial that explains NSUserDefaults
I've been reading up on saving objects, preserving state etc, but I'm still a little confused on the route I should take when saving objects that are created from my app. I have built an app where a user can create a Radio Station with the Genre, name and frequency. Once a user hits save, a "RadioStation" object is created using a custom class and is stored in an NSMutableArray that is placed in the RootViewController. While RadioStation objects can be stored in this array and are displayed correctly in the table view, it's obvious that once the application quits, these are no longer going to be held by the application.
At this point I'm not sure how I should begin to architect this design. Do I need to set up a plist? Should I use Core Data with a SQLite DB? Do I need to research iOS object serialization for both these scenarios? Or is there an more straight forward way that I'm not aware of?
There are three ways to persist data locally:
Store objects in a database using managed objects or SQLite
Store objects in a file in the sandbox using various classes' writeToFile
Store the data in NSUserDefaults
How you persist your object data depends on how you're using it, and what type of data you're saving. CoreData makes sense if you have a lot of objects of the same type and SQL's search and sorting mechanisms would be useful. I tend to use the sandbox for very large files, eg images, sound files, and large agglomerations of data bounced through NSData. And I use UserDefaults for small amounts of data that might be considered "preferences".
You can put anything anywhere you want, and I suggest being familiar with all three mechanisms when you start a new project. Additional techniques, like using NSCoding to serialize and deserialize classes, can be used to make saving data easier. Note that once you've implemented NSCoding, you could store data anywhere and even send it over the wire.
For your RadioStation, I would personally use UserDefaults. The benefit of using NSCoding is that, once you implement initWithCoder and encodeWithCoder, you can stream a hierarchy of objects (eg an array of custom objects, each of which might contain a dictionary, array, or custom object, etc) fairly easily. If the only thing you're saving is an array of strings, then directly using UserDefaults is easy enough.
The most powerful approach is to make your custom object a subclass of NSManagedObject, and store it in an NSManagedObjectContext using Core Data. On iOS this will always use an sqlite database, on Mac OS X you can use sqlite, xml, or a proprietary binary format (smaller/faster than xml).
Depending on how complicated your data structure is, and how likely it is to change in future, this technique may or may not be too complicated for your app. It's a lot of work to setup, and the API is very complicated, but it's the best choice if you need to store tens of thousands/millions of objects in a file.
For your app, I would have a single sqlite file containing all of the radio stations in the app.
The simplest option, is to implement the NSCoding protocol in your custom object's class. Documented here:
http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Archiving/Articles/codingobjects.html#//apple_ref/doc/uid/20000948-BCIHBJDE
The basic theory is your object writes or reads all it's data to a "coder", and then passes the coder on to any child object(s). Outside of the class, you use an "archiver" or an "unarchiver" class to coordinate everything.
Once your custom class implements NSCoding you can read/write it to the disk with:
myObject = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
[NSKeyedArchiver archiveRootObject:myObject toFile:filePath];
This is a very simple approach, but it has a few drawbacks, for example you will need to figure out your own way to support different versions of the file format (perhaps with a different file extension for example).
Many classes in Cocoa/CocoaTouch already implement NSCoding, so they can be written to a file in this fashion (including NSArray, NSString, NSNumber, etc).
For your app, i would use this to store each radio station in a single file. When the app launches, load all the radio stations from a directory. You should consider enabling iTunes drag/drop filesharing for your app, so users can easily share radio station files with their friends or between devices.
This would also fit in well with iCloud for syncing between devices, I haven't looked into iCloud much, but I expect one file per radio station will be the ideal way to implement iCloud syncing.
No need for such things. If you only have like one thing to save, then research this method of NSArray:
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
I your user can save many radio stations, then you might want to look into CoreData, which has a bit of a curve, but ultimately will be the easiest way.