I am working on an application where the user is able to draw on the screen with their finger. I am using UIBezierPath for this. I need to persist this data which is an NSArray containing multiple BezierPath objects. What is the best way to go about this? Store in coredata, store in a file using NSData? Much obliged.
Are you expecting to have to store multiple objects? Will you need to be able to fetch them based on some filter or ordering? I recommend using Core Data to save yourself a decent amount of work in packing/unpacking the data. There isn't really a reason to store it in a file.
edit:
As the other answer said, you just archive it to NSData. The UIBezierPath class adheres to the NSCoding protocol so you can do something like this to archive it:
NSData *bezierData = [NSKeyedArchiver archivedDataWithRootObject:bezierPath];
You can persist that NSData object in Core Data.
To decode the archive, assuming we have a bezierData NSData object, you can do something like:
UIBezierPath *bezierPath = [NSKeyedUnarchiver unarchiveObjectWithData:bezierData];
Archive the UIBezierPath to NSData, and store it as an attribute of type NSData in CoreData. You can have an easier API if you make it a transformable attribute.
It's pretty easy to do, especially for classes that already support archiving.
See this document for more information.
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html
Related
Looking into Realm.io and trying to figure out of how to store customer types like CMTime, CMTimeRange, I'm using to store them in NSData in CoreData based on these ideas;
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html#//apple_ref/doc/uid/TP40001919-SW1
I would like just before the object gets saved, to store all the customer types in an NSData blob.
Realm does not currently have an equivalent to awakeFromFetch or willSave, but you can approximate that functionality by using computed (unpersisted) properties.
I have an NSMutableArray that contains NSMutableDictionary's. Each dictionary has an AVAsset, an NSURL, an NSString, and two UIImages. I want to save my array to disk so that each time I close and open my app, I can load the array and convert the URLs's to NSData objects in order to play audio and use the AVAssets for some other actions. I know I can save and load my array using initWithContentsOfFile and writeToFile:atomically and this answer is pretty informative: Saving a NSArray. However, that answer was from 2009. Is there a better way of saving and loading an array these days?.
As for the answer you linked, the answer is still valid. And according to it, you cannot store it the way it mentions. This is because array must be plist format compatible in order to be saved like that. When you parse your array down to lowest element hierarchy, you have UIImage which is just an object pointer and doesn't make sense.
One practical way would be store UIImages as separate files, and store their paths as part of your NSMutableDictionary objects. Same holds true for AVAssets. Off course you need to engineer the solution to fully accomplish this goal.
One more way to store non-plist compatible objects is to use archiving and unarchiving feature. Refer to the documentation. Here, make sure that each object in the tree follows protocol NSCoding (Probably, AVAsset in your question does not conform to it, so you need a way to work around it). For an example, see this answer and search the likes of it.
I have the following requirement: create and populate a SQLite database with data from a .xml file, this file can have a different structure any time so I cannot create the NSManagedObjectModel with Xcode, it must be at runtime. I've successfully created a NSManagedObjectModel programmatically, created the persistent store and populated the sqlite file with data from the .xml . However, the next time I use the app the persistent store is not compatible with the NSManagedObjectModel (I don't want to recreate the Model every time I run the app, just the first time). Is there any way to save the model I created programmatically and load it the next time it is needed? All I can see in the examples are models being loaded from the NSBundle.
Is there any way to save the model I created programmatically and load it the next time it is needed?
Yes. NSManagedObjectModel conforms to NSCoding, which means that you can easily convert it to/from NSData, and saving and reading NSData is easy.
To save a model:
NSString *modelPath = // path where you want to save
NSData *modelData = [NSKeyedArchiver archivedDataWithRootObject:self.managedObjectModel];
[modelData writeToFile:modelPath atomically:YES];
To read a saved model:
if ([[NSFileManager defaultManager] fileExistsAtPath:modelPath]) {
NSData *savedModelData = [NSData dataWithContentsOfFile:modelPath];
NSManagedObjectModel *savedModel = [NSKeyedUnarchiver unarchiveObjectWithData:savedModelData];
}
I'm not sure if you are saying that the data in the xml file is changing each time or what. It sounds like you are referring to the data, not the data model. I can't answer specifically, but I would take the approach as follows.
If the data in the xml file is structured the same or close to the same each time, I would create a data model to match that.
Then I would write some sort of parser class that would read the xml and parse it into the Core Data data store according to you "ManagedObjectModel" or data model.
I have seen the error you are talking about when you change the datastore outside of Core Data. You need to let Core Data handle all the reading and writing to the data store or else Core Data will tell you basically that "Your Persistent Store was created or altered by something other than your ManagedObjectModel". I think this is what is happening.
I know I am not using the terminology exactly as Core Data puts it, but Core Data is confusing and I'm trying to convey the message and understanding.
I would also look in to using MagicalRecord. It Drastically makes Core Data easier to work with and there is a great tutorial on www.raywenderlich.com which you can find Here
I really hope this helps you out some. If not, please post some sample code or maybe an example of that xml you are referring to.
Good Luck
I'm new to iOS but have plenty of experience with c++ and Python. I'm trying to figure out how to read a plaintext file I have on my computer into an NSArray in xcode. In c++ I would do this:
while(istr>>string) myArray.push_back(string);
However, I need to create a local copy to be stored on the iOS device. Is there a way I can package this data so that a local copy of JUST THE ARRAY will be stored on the device? I was thinking of maybe doing something with a JSON serialization or something.
Should I really just suck it up and do this:
NSArray myArray = [[NSArray alloc] initWithObjects: #"myInfo", nil];
I just want a more elegant way to handle this, I guess.
I think maybe you're thinking a little too C about this. In C and C++, strings are arrays of bytes. In ObjC, there's an object for that. It's called NSString, and it's probably what you should be storing plaintext in.
It even has an easy class method to help you out with this if you already have a byte array:
+(id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc
See the NSString documentation for more details.
As to storing it on the device, there are solutions that range from the simple (NSUserDefaults) to the complex (Core Data), but pretty much anything will expect plain text be in an NSString.
EDIT:
The title of this question talks about reading the string from the filesystem. First step is to get the bytes of the file into an NSData object. The easy way:
+(id)dataWithContentsOfFile:(NSString *)path
Then make a string out of the data with this initializer of NSString:
-(id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding
I don't know if this can help you, anyway if you just need to store an array of data to filesystem and deserialize it back to NSArray, an easy way is to use plists.
It is a convenient way to store a small amount of data, without any kind of relationship (there is Core Data for that). The main advantage is that you can store in it NSArray, NSDictionary, NSNumber, NSString, NSDate and NSData (so any kind of binary information) and they get automatically serialized and deserialized through some simple methods.
You can write an NSArray to a file in this way:
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)flag
and deserialize it back with this:
+ (id)arrayWithContentsOfFile:(NSString *)aPath
If you just want to provide some initial data to your app, and it is for example an array of strings or something similar, you can manually add a plist to your project by going to File->New->File and choosing Resources->Property list, and fill it by hand.
You can read more at https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/PropertyLists/Introduction/Introduction.html
I have an NSDictionary, which contains a bunch of NSManagedObjects.
I can then use NSKeyedArchiver to write this to an NSData object.
These are generated using this method. Which works fine and allows me to save a section of schema to disc and then read it back as a new set of objects in the core data model.
If I use either archivedDataWithRootObject:
or archiveRootObject:toFile:, as per the documentation
I can see that the format of the archive is NSPropertyListBinaryFormat_v1_0, whereas I want to serialise in NSPropertyListXMLFormat_v1_0, so that I can write my objects to a file and then process them elsewhere as plain old XML. (In fact I want to generate documents from them on a Windows based system.)
1) Is there a way I can do this? If so how?
2) Is there a better approach.
I want to maintain the serialised nature, since I also want to send the file back to the iOS device later and recreate the object model.
Create your own instance of NSKeyedArchiver with initForWritingWithMutableData:.
Set the format with setOutputFormat:NSPropertyListXMLFormat_v1_0.
Encode your root object with encodeObject:forKey:.
Call finishEncoding.
To unarchive the data you encoded in this way, you have to similarly instantiate an NSKeyedUnarchiver.
Thanks Ole! I was heading in that direction, but was not sure if it was the right way. Here is what I did in code in case it helps someone.
NSDictionary *dataAsDictionary=[self toDictionaryBlockingRelationships:blockRelationship];
NSString *savePath = [#"~/Documents/Saved.data" stringByExpandingTildeInPath];
NSMutableData *xmlData=[NSMutableData data];
NSKeyedArchiver *archive=[[NSKeyedArchiver alloc ]initForWritingWithMutableData:xmlData];
[archive setOutputFormat:NSPropertyListXMLFormat_v1_0];
[archive encodeRootObject:dataAsDictionary];
[archive finishEncoding];
if(![xmlData writeToFile:savePath atomically:NO]){
NSLog(#"Failed to write to file to filePath=%#", savePath);
}
[archive release];