I'm using Parse as a backend and it doesn't like NSData. I have an array that I need to store that holds the data of different audio files in each of its elements. I know I can convert my data to NSString, but I'm not sure what kind of encoding is appropriate. The strings will need to be converted back to an NSData objects. Any suggestions?
PFFile is the class you want, you can create it from NSData if you want to save binary files: https://parse.com/docs/osx/api/Classes/PFFile.html
Related
When writing data to file (e.g. Thumbnails for caching, user data, etc.), how do you deal with the fact that the iDevice could not be able to write your data to file since the disk is full?
Will NSFileManager throw an exception in case of low disk space?
What's the designated way to deal with this and to inform my user that there's very little disk space left for his data? (I'm saving a fair amount of different data at different places in my app and searching for a common way to deal with it.)
As you mentioned in the comments that you want to save NSDictionary. If you only want to know whether the file is saved successfully or not, you can inspect the return value of the
writeToFile:atomically: function.
Return Value
YES if the file is written successfully, otherwise NO.
More information under the NSDictionary's Storing Dictionaries Section.
Alternatively,
If you want to get a more detail error message for the failure (such as out of disk space, folder not exist and etc.), then you can convert the NSDictionary to NSData before saving it.
NSDictionary to NSData:
NSData *myData = [NSKeyedArchiver archivedDataWithRootObject:myDictionary];
NSData to NSDictionary:
NSDictionary *myDictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:myData];
The benifits is that you will also have access to this API -writeToFile:options:error:.
If there is an error writing out the data, upon return contains an NSError object that describes the problem.
Also more detail could be found under the Storing Data Section of NSData.
I think that's the best you can do in case there is a low disk space problem on the device.
I need to save images which I get from server using
[[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:URL]]];
To NSMutableDictionary - it's ok for me, I'm doing it like this (it is in loop for every fetched image):
[self.imagesDict setObject:image forKey:[[xmlArray objectAtIndex:x] objectForKey:#"_img"]];
And than, I need to save it to disc. There were two solutions for me, but no one works... :-(. First one was save it do NSUserDefaults and second is save it to .plist file to root of iPhone. I want to go with that .plist, so I did:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pathLD = [documentsDirectory stringByAppendingPathComponent:#"imagesDict"];
[self.imagesDict writeToFile:pathLD atomically:YES];
But when I try to NSLog it, it's not working. However when I save to dictionary some string instead of image, it works like a charm. So can someone help me please what I'm doing wrong? Thanks a lot!
You can not store the UIImage objects directly. Put their NSData inside the NSDictionary to be able to save them. Either the downloaded NSData or create it new via UIImagePNGRepresentation(image)
From the Dokumentation of NSDictionary's writeToFile:atomically:
This method recursively validates that all the contained objects are property list objects (instances of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary) before writing out the file, and returns NO if all the objects are not property list objects, since the resultant file would not be a valid property list.
I can see two problems. First, you should really use .plist as the file extension of your dictionary. But more importantly, you're trying to save a dictionary that contains an object (UIImage) that cannot be serialized to a plist. Plists only support a limited number of object types, such as NSNumber, NSData, NSString. Looks at the writeToFile:atomically: description in the NSDictionary class reference. It has a list of what's allowed. If you want to save an image to a plist, you have to serialize it yourself into an NSData. I don't think it's a good idea, though, because the NSData representation might be a lot larger than the original image. I think you would be better off finding another way to do this.
I'm just confused about when to use NSData. I'm about to get some data stored in the server (I'm just using dropbox here instead for some practice.)
What I did so far is
Made some p-list storing 2 arrays, one stores string object , and the other stores string objects of the public URL for the audio data.
When I created the NSString from the plist , I didn't use NSData object
When I created the NSAudio Player with data stored in the same project folder, I didn't use NSData object
When I created the NSAudio Player with data stored in a server, I used the NSData
I just don't understand when to use NSData object properly. I checked the app document, but it says "Data objects let simple allocated buffers" What is the allocated buffers here?
Thanks,
NSData is just a wrapper for a byte array. Anywhere that you specifically need a byte array you can either use a byte array and do all manipulations manually (accessing and manipulating the data) or you can wrap it in an NSData (or NSMutableData if you need to modify the bytes) and use Apple provided functions to easily access or modify the data.
The allocated buffer is the byte array stored inside the NSData wrapper. Say you have an audio object on disk that you want to modify one byte in the middle of. You could load that data from disk into an audio element, but then you can't modify it. If you load it's byte values from disk into an NSMutableData you can have access to the bytes directly, modify whatever you would like using simple methods provided to the NSMutableData class, then same the audio element back to disk (or load that data directly into your audio element).
The best use of an NSData object is only when you need it, just like any other class. If you specifically need the functionality to run your app, then use it. Otherwise it is likely just an added step that is not required (ex data-on-disk -> audio-element vs data-on-disk -> NSData -> audio-element).
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];