I have a large MKOverlay that I would like to be saved in Core Data so that I don't have to create it later. Since this isn't one of the types that you can choose in Core Data, how do I go about saving it?
Do I need to somehow encode it first?
Do I then need to decode it when using?
What kind of object do I select in core data when creating a new property?
Thanks guys.
If you do not need to query for different overlays and you're not using core data elsewhere in your project, then you're probably better off caching the overlay on disk as an encoded NSArray.
However, if you're already using Core Data or you're caching multiple overlays then you can encode/decode the overlay in a field of type NSData. Add additional fields to the entity so you can query for the specific overlay you're looking for.
In iOS 5, you can enable optional storage of NSData fields in an external file by selecting the "Allows External Storage" option. Core Data will apply a size-based heuristic to determine if a blob or external file will result in better performance.
MKOverlay conforms to NSCoding, so you can encode and decode an entire array of MKOverlay objects using an encode method of NSKeyedArchiver and store the result in a binary field in your entity. You'll likely want + (NSData *)archivedDataWithRootObject:(id)rootObject on NSKeyedArchiver and + (id)unarchiveObjectWithData:(NSData *)data on NSKeyedUnarchiver
See the Archives section in the Archives and Serializations Programming guide for details of creating a keyed archive at: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Archiving/Articles/archives.html
You can write a custom accessor for the entity's binary field that encodes and decodes the overlay array for you. Another option is to create a value transformer that encapsulates the encoding and decoding operations. The end result would be an overlays array property that you can set and read via entity.overlays.
I believe you can use Apple's NSCoding libraries to convert the object to and from a serialized state. However, Core Data may support saving objects, but NSCoding lets you save any class that implements it anywhere, including a string sent to a server, a file written to disk, or if you're as bad a programmer as me, an NSUserDefaults entry.
edit- You may have to implement NSCoding into your own class based on MKOverlay by adding read and write methods, I'm uncertain.
Why not instead save the properties (size, color, coordinates, etc can all be described with NSNumbers and those can be stored in Core Data natively) and recreate the MKOverlay when needed. I think that's a much more efficient approach to be honest. I'm not sure how much of an impact creating an object has, so prove me wrong if I'm wrong.
You need to take the large dataset that composes the overlay and turn those individual data nodes into NSManagedObjects to be stored in CoreData.
I mean, you probably COULD just NSCoder the entire thing into one giant datablob, but at that point, you might as well just write the thing to a flat file (which frankly might be better if all you want to do is read/write it without changing it).
Don't use Core Data unless you're going to be doing legit querying or piecemeal changes to the dataset.
Related
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.
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.
I am not very "fluent" with Ocean serialization .
Can I serialize an entire Petrel Property (Properties, Grids or any other Petrel/Ocean's objects) into my custom DataSource? Will I be able to load it back?
Is there any good practice/pattern to do that?
Some code sample would be welcome!
Do you have an established DataSource already? The persistence back end (SQL? XML?) used by your DataSource dictates how data is stored. Any data you want to persist through the DataSource must be converted to your back-end's format.
Note that there is no such thing as "Ocean serialization" with DataSources - you (and only you) are in complete control of the DataSource. Usually, you are actually providing it as a service to Ocean, so that it, given a Droid, can resolve one of your objects (be they e.g. custom domain objects, workstep argument packages or seismic attribute argument packages).
Now, from your question, it sounds like you are seeking to store deep copies of the Petrel data you mention. Is this really the case? If so, I'm afraid you'll need to make your own data structures representing this data, mirroring what you can read out through Ocean's APIs.
If what you really want to store is a weak reference to the Petrel data (implementing IIdentifiable), you'll want to persist the contents of each object's Droid - a much simpler task.
Then, when your persisted data is resolved from your DataSource, you'd rebuild the Droid(s), which can then be resolved themselves (using some other DataSource but your own), resulting in a regular strong .NET reference to the object - assuming of course that this data is present in the currently loaded project.
The SimpleDataSourceExample in the Ocean SDK demonstrates a simple DataSource backed by a .dat file using BinaryFormatter. This is relatively trivial to modify to other back-ends. I strongly recommend XML over BinaryFormatter, but if you intend to store considerable amounts of bulk data, you should consider a database. At Blueback Reservoir, XML has served our needs very well.
A minor caveat: make sure that the objects you store in your DataSource implement IDisposable (as well as IIdentifiable), to free resources in the DataSource.
Hi could anyone point me in the right direction with a tutorial, guide or sample code, thanks, Sami.
The answer given by shreyasva is close but somewhat misleading.
First, parsing the XML into an easily-managed Cocoa data structure is perfectly correct. For performance reasons, you shouldn't be tying your table's datasource directly to the XML. yan.kun's suggestion is certainly possible but if you have "more than a little" data, you very well could run into performance problems. I highly recommend just parsing the data into an NSArray of NSDictionary objects for longer data sets.
Second, Core Data is a bit overkill if you don't plan to persist the XML document in some other way or if you only have a handful of objects. Overkill by a long shot. It's also not necessary (and often not reasonable) to shoehorn every data structure in your app into Core Data without good reason. An NSDictionary instance will work just fine for caching the parsed data for consumption by a table view.
Third, there is no -tableView:cellForRowAtIndexPath: method. This seems to be confusing NSTableView with UITableView. Since you specified the Mac tag, look into the NSTableViewDataSource protocol. Cocoa Bindings is not "better than" or a "replacement for" the data source protocol. It's an "alternative to". You can either load your parsed data into an NSArrayController (an array of dictionaries, one per "record", for example) and bind the table columns to it (each column is bound to a key in the dictionaries in the array controller's arrangedObjects) or just use the (easy) table data source protocol that takes literally two minutes of copy/paste from the docs to get up and running.
Ill give you an idea of the architecture.
Parse the XML using any popular XML parser NSXMLParser is fine.
Store the data using core data objects, if data is not too much, keep it in memory.
Load data in tableView:cellForRowAtIndexPath:
Alternatively, if you just want to list the content, without editing capabilities, you can load the XML into a NSXMLDocument and bind the TableView via xPath.
The iOS docs differentiate between "serializing" and "archiving." Is this a general distinction (i.e., holds in other languages) or is it specific to Objective-C? Also, what is the difference between these two?
This is a case of one being the other some (but not all) of the time.
Wikipedia has this to say about serialization:
"Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be "resurrected" later in the same or another computer environment"
So, archiving may only be serialization, but it could also be the combination of serialization and compresssion, for example. Or perhaps it adds some kind of header info. So serialization is a form of archive, but an archive is not necessarily a serialization.
This isn't really specific to iOS - these terms are thrown around all over. Their specific meaning in the context of iOS could be quite specific, though.
I was actually trying to look for their difference from IOS perspective. Adding the following for people interested :
Purpose:
Archiving is used to store object graphs. complete data model can be archived and restored easily. The way Nib files work can be considered as example for archiving.
Serialization is used for storing arbitrary hierarchy of objects.
The wat plist files work can be considered as example fo serializations.
Differences(excerpts from Archives programing guide):
"The archive preserves the identity of every object in the graph and all the relationships it has with all the other objects in the graph."
Every object encoded within the context of rootObject invocation is tracked. If the coder is asked to encode an object more than once, the coder encodes a reference to the first encoding instead of encoding the object again.
"The serialization only preserves the values of the objects and their position in the hierarchy. Multiple references to the same value object might result in multiple objects when deserialized. The mutability of the objects is not maintained."
Implementation differences:
Any object that implements NSCoding protocol can be archived where as Only instances of NSArray, NSDictionary, NSString, NSDate, NSNumber, and NSData (and some of their subclasses) can be serialized. The contents of array and dictionary objects must also contain only objects of these few classes.
When to Use:
property lists(serialization) should be used for data that consists primarily of strings and numbers. They are very inefficient when used with large blocks of binary data.
It is worthy to Archive objects other than plist objects or storing large blocks of data.
Generally speaking, Serialization is concerned with converting your program data types into architecture independent byte streams. Archiving is specialized serialization in that you could store type and other relationship based information that allow you to unserialize/unmarshall easily. So archival can be thought of as a specialization and subset of Serialization. For Objective-C
Serialization converts Objective-C
types to and from an
architecture-independent byte stream.
In contrast to archiving, basic
serialization does not record the data
type of the values nor the
relationships between them; only the
values themselves are recorded. It is
your responsibility to deserialize the
data in the proper order. Several
convenience classes, however, do
provide the ability to serialize
property lists, recording their
structure along with their values.
With C++ boost serialization --
http://www.boost.org/doc/libs/1_45_0/libs/serialization/doc/index.html
Here, we use the term "serialization"
to mean the reversible deconstruction
of an arbitrary set of C++ data
structures to a sequence of bytes.
Such a system can be used to
reconstitute an equivalent structure
in another program context. Depending
on the context, this might used
implement object persistence, remote
parameter passing or other facility.
In this system we use the term
"archive" to refer to a specific
rendering of this stream of bytes.
This could be a file of binary data,
text data, XML, or some other created
by the user of this library.