recreate arraywithobjects as a plist - iphone

i know its stupid but how do i recreate this array to a plist list
candyArray = [NSArray arrayWithObjects:
[Candy candyOfCategory:#"chocolate" name:#"chocolate bar"],
[Candy candyOfCategory:#"chocolate" name:#"chocolate chip"],
[Candy candyOfCategory:#"chocolate" name:#"dark chocolate"],
[Candy candyOfCategory:#"hard" name:#"lollipop"],
[Candy candyOfCategory:#"hard" name:#"candy cane"],
[Candy candyOfCategory:#"hard" name:#"jaw breaker"],
[Candy candyOfCategory:#"other" name:#"caramel"],
[Candy candyOfCategory:#"other" name:#"sour chew"],
[Candy candyOfCategory:#"other" name:#"peanut butter cup"],
[Candy candyOfCategory:#"other" name:#"gummi bear"], nil];
thanks for anyones help!

Try like this but before that include your array and then follow below:-
NSFileManager *fileManager =[NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask,YES);
NSString *desktopDirectory = [paths objectAtIndex:0];
NSString *path = [desktopDirectory stringByAppendingPathComponent:#"yourfile.plist"];
NSMutableDictionary *mut=[NSMutableDictionary dictionary];
[mut setObject:candyArray forKey:#"yourKey"];
If ([mut writeToFile:path automatically:YES])
{
NSLog(#"file created");
}

Andy,
Hussain's answer is close but will fail when archiving the custom type.
Simple answer. You must adopt the NSCoding protocol since your using a custom class (Candy). Implement the following tasks initWithCoder, encodeWithCoder and the default archiver will take care of the rest. If you would like to archive in other formats (Binary etc) please reference NSData and NSCoder (NSKeyedArchiver). JSON is also another good lean option.
If this is too much trouble forgo custom objects and nest primitives in arrays or dictionaries. This is discouraged for complex custom types and will build technical debt but encouraged for simple structures. Wanted to share Apple best practices.
Supported plist types (iOS)
NSString,
NSNumber,
NSDate,
NSData,
NSArray,
NSDictionary
Simple Example (NSArray, NSDictionary)
https://developer.apple.com/library/mac/documentation/cocoa/Conceptual/Archiving/Articles/serializing.html#//apple_ref/doc/uid/20000952-BABBEJEE
Full Reference Doc for Custom Objects (NSCoding)
https://developer.apple.com/library/mac/documentation/cocoa/Conceptual/Archiving/Archiving.html#//apple_ref/doc/uid/10000047i

Related

Objective-C - how to save and load an array containing images

Good evening everyone, I was hoping you could help with an Objective-C question I have.
In my app, I have a mutable array that contains 16 objects; the objects being images.
I would like to save and load the array so that the images are retained when the user quits the program.
I am new to data persistence and I can see there are several ways of saving and loading data and I am familiar with the NSUserDefaults method of saving and loading data. I am aware though that you cannot save arrays with images in this way.
Could someone please explain, perhaps with an example of the best and simplest way of saving and loading an array with images? Any help would be great as I'm unsure the best way to go with this.
Thanks everyone in advance!
Consider using NSKeyedArchiver.
// Archive
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:theArray];
NSString *path = #"/Users/Anne/Desktop/archive.dat";
[data writeToFile:path options:NSDataWritingAtomic error:nil];
// Unarchive
NSString *path = #"/Users/Anne/Desktop/archive.dat";
NSMutableArray *theArray = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
This way you can be sure the unarchived array is identical to the original.
All classes conforming to the NSCoding protocol can be used by NSKeyedArchiver.
Note: You can use any extension.
Response to comment:
The following should work on iOS:
// The Array
NSMutableArray * array = [[NSMutableArray alloc] init];
// Determine Path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [ [paths objectAtIndex:0] stringByAppendingPathComponent:#"archive.dat"];
// Archive Array
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
[data writeToFile:path options:NSDataWritingAtomic error:nil];
// Unarchive Array
NSMutableArray *theArray = [NSKeyedUnarchiver unarchiveObjectWithFile:path];

How can I write this XML example to an XML file?

How do I write this so it will be saved in an XML file?
<Stations>
<station id="1">
<title>Lehavim Railway station</title>
<latitude>31.369834</latitude>
<longitude>34.798207</longitude>
</station>
</Stations>
I have this part of code, but I don't know how to arrange it so that it will be saved as shown above.
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString * filePath = [paths objectAtIndex:0];
filePath = [filePath stringByAppendingPathComponent:#"favorite"];
filePath = [filePath stringByAppendingPathExtension:#"xml"];
NSDictionary *station = [NSDictionary dictionaryWithObjectsAndKeys:
#"Lehavim Railway station",
#"31.369834",
#"34.798207",
, nil ];
[station writeToFile:filePath atomically:YES];
I also don't know how to change the id in the station part.
On the local iOS file system, XML files look the same as the plist files written out by NSDictionary or NSArray so programmers can frequently "cheat" (or take a short cut?) by writing out nested dictionaries or arrays and considering them XML files.
Except these files are not XML. And you can't write out XML-style attributes (i.e. the id = "1" bit in your example up there) via the standard NSDictionary or NSArray writeToFile: methods.
You need to decide on a class that creates XML objects and allows you to write them out.
Here is a related question with a selection of answers & choices that can help you figure out the right way to go. For my own projects, I really like libxml2.

Writing an array of NSData to file

I am trying to save an array of images to the documents folder. I managed to save an image as NSData and retrieve it using the method below, but saving an array seems to be beyond me. I've looked at several other questions that relate and it seems I'm doing everything right.
Adding the image as NSData and saving the image:
[imgsData addObject:UIImageJPEGRepresentation(img, 1.0)];
[imgsData writeToFile:dataFilePath atomically:YES];
Retrieving the data:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"imgs.dat"];
[self setDataFilePath:path];
NSFileManager *fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:dataFilePath])
imgsData = [[NSMutableArray alloc] initWithContentsOfFile:dataFilePath];
So, writing an image as NSData using the above works, but not an array of images as NSData. It inits the array, but it has 0 objects, which isn't correct, since the array I am saving has several. Does anyone have any ideas?
First of all, you should brush up Cocoa Memory Management, the first line of code is a little bit of a worry.
For data serialisation, you may like to have a go with NSPropertyListSerialization. This class serialises arrays, dictionaries, strings, dates, numbers and data objects. It has an error reporting system, unlike the initWithContentsOfFile: methods. The method names and arguments are a bit long to fit on one line, so sometimes you may see them written with Eastern Polish Christmas Tree notation. To save your imgsData object, you can use:
NSString *errString;
NSData *serialized =
[NSPropertyListSerialization dataFromPropertyList:imgsData
format:NSPropertyListBinaryFormat_v1_0
errorDescription:&errString];
[serialized writeToFile:dataFilePath atomically:YES];
if (errString)
{
NSLog(#"%#" errString);
[errString release]; // exception to the rules
}
To read it back in, use
NSString *errString;
NSData *serialized = [NSData dataWithContentsOfFile:dataFilePath];
// we provide NULL for format because we really don't care what format it is.
// or, if you do, provide the address of an NSPropertyListFormat type.
imgsData =
[NSPropertyListSerialization propertyListFromData:serialized
mutabilityOption:NSPropertyListMutableContainers
format:NULL
errorDescription:&errString];
if (errString)
{
NSLog(#"%#" errString);
[errString release]; // exception to the rules
}
Check the contents of errString to determine what went wrong. Keep in mind that these two methods are being deprecated in favour of the dataWithPropertyList:format:options:error: and propertyListWithData:options:format:error: methods, but these were added in Mac OS X 10.6 (I'm not sure if they're available on iOS).

iPhone SDK: How do I properly save user-inputted information into a .plist or other file?

I've looked through the SDK documentation and through other questions that have been asked, and I am still a little confused on how exactly to do this. I had been previously been working with the following code, though it does not give the desired result of a .plist file. Besides mentioning the IBAction in the header files in this code in the .m file, is there anything else that needs to be added or anothe method I should be taking? Thanks!
My Code:
- (IBAction)fedDog {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"dogsFedDays.plist"];
NSMutableArray *dogsFedSave = [NSMutableArray arrayWithCapacity: 100];
for (int i = 0; i < 100; i++) {
NSDictionary *myDict = [[NSDictionary alloc] initWithObjectsAndKeys:
date[i], #"string",
fed[i], #"Yes",
nil];
[dogsFedSave addObject:myDict];
[myDict release];
}
if (![dogsFedSave writeToFile:path atomically:YES])
NSLog(#"not successful in completing this task");
}
I'm assuming that -writeToFile is returning NO so you're seeing your NSLog statement (correct me if I'm wrong). If that's the case, then the issue must be that some object in either your date array, or fed array is not any of the allowed object types for property lists which includes: NSString, NSData, NSArray, or NSDictionary. NSNulls are not allowed. From the docs for writeToFile:
This method recursively validates that
all the contained objects are property
list objects 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.

Plist not saving from dictionary (to Documents)

I've been trying to save a plist of a NSDictionary to my app's Documents folder. I haven't tried this on the device yet but I'd like it to work on the simulator for testing purposes. The [self createDictionaryFromChoreList] method just creates a NSDictionary from some data in another class of mine. I've pretty much copied/pasted this code from the web documents and when I go to see if the file was saved or not, I find that it isn't. Here is the method block.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistName = [[NSString alloc] initWithFormat:#"%#chores.plist", self.firstName];
NSString *path = [documentsDirectory stringByAppendingPathComponent:plistName];
NSDictionary *choresDictionary = [[NSDictionary alloc] initWithDictionary:[self createDictionaryFromChoreList]];
[choresDictionary writeToFile:path atomically:YES];
Any help is greatly appreciated. Thanks in advance.
-S
You should also capture the BOOL returned by writeToFile:atomically:. That will tell you if the write succeeded or not.
Also, are you sure you are looking in the right documents folder? If you have more than one app in the simulator its easy to open the wrong app's documents folder in the Finder. I did that once and it cost me a couple of hours of frustration.
Edit01:
writeToFile:atomically: returning false explains why no file exist. The simplest explanation is that something in the dictionary is not a property list object.
From the NSDictionary docs:
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.
It just takes one non-plist object buried deep in a dictionary to prevent it from being converted to a plist.
Don't forget serialize the plist data:
Here is a snippet of code that I use for writing information to a plist
NSString *errorString;
NSData *data = [NSPropertyListSerialization dataFromPropertyList:plistDict
format:NSPropertyListXMLFormat_v1_0
errorDescription:&errorString];
[plistDict release];
if (!data) {
NSLog(#"error converting data: %#", errorString);
return NO;
}
if ([data writeToFile:[XEraseAppDelegate loadSessionPlist] atomically: YES]) {
return YES;
} else {
NSLog(#"couldn't write to new plist");
return NO;
}
This is something I whipped up really quickly and it correctly writes a plist directory of name and company to the documents directory. I have a feeling your dictionary creation method might have an issue. Try this out for yourself, then add your code and make sure it works.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *plistDirectory = [paths objectAtIndex:0];
NSString *plistPath = [plistDirectory stringByAppendingPathComponent:#"userCompany.plist"];
NSArray *userObjects = [[NSArray alloc] initWithObjects:#"Joe", #"Smith", #"Smith Co", nil];
NSArray *userKeys = [[NSArray alloc] initWithObjects:#"First Name", #"Last Name", #"Company", nil];
NSDictionary *userSettings = [[NSDictionary alloc] initWithObjects:userObjects forKeys:userKeys];
[userSettings writeToFile:plistPath atomically:YES];
Is it correct, that the name of file your writing to is:
SOEMTHINGchores.plist?
Created via:
NSString *plistName = [[NSString alloc] initWithFormat:#"%#chores.plist", self.firstName];
Also, what is the output of:
[choresDictionary print];
Some additional info would help to debug this.
Where exactly are you looking for the file?
I have the exact same code and it works fine for me.
Just that I have to dig deep to get the file. Something like:
/Users/myUserName/Library/Application Support/iPhone Simulator/User/Applications/0E62A607-8EEB-4970-B198-81CE4BDDB7AA/Documents/data.plist
And the HEX number in the path changes with every run. So I print the file path with every run.
Insert a break point at
NSDictionary *choresDictionary = [[NSDictionary alloc] initWithDictionary:[self createDictionaryFromChoreList]];
now when you step out drag your mouse over choresDictionary and check in the tooltip that its size is not 0x0 or you can simply do an NSLog of the choresDictionary
like NSLog(#"%#",choresDictionary); I think your dictionary has 0 key key value pairs thats why you are getting null into your documents folder.
Thanks,
Madhup
I was running into this issue as well. In my case it turned out that I was using NSNumbers for keys - which is not valid.