Can't read from plist - iphone

I have a plist with an array at top level and then a number of items within it.
When I try the following
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"Spots.plist"];
spotsArray = [[NSMutableArray arrayWithContentsOfFile:finalPath] retain];
the array spotsArray is empty.
I have tried a number of things and have used plists successfully before. I dont know what the issue is now.
What could be causing the issue, my plist looks like this

It's not an array at the top level it's a dictionary with a single item called 'New Item'.
Try NSMutableArray *mutableArray = [[[NSDictionary dictionaryWithContentsOfFile:finalPath] objectForKey:#"New Item"] mutableCopy] autorelease]

This should mean that your .plist file does not exist or not readable.
Try to create the file with writeToFile at the same path to verify it works. (It can also help you to verify the directory)

Related

Add & Remove Array Items inside a plist

I have problem with adding and removing items in an array inside a plist file in XCODE.
I'm able to read the array by following code:
// Path to the plist (in the application bundle) ------>>>>>
NSString *path = [[NSBundle mainBundle] pathForResource:
#"Fav" ofType:#"plist"];
// Build the array from the plist ------>>>
NSDictionary *favs = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
Resepies = [favs objectForKey:#"Root"];
And this my plist structure
The senario is to let the user add and remove specific item from the array at a time.
try this code -
NSString *path = [[NSBundle mainBundle] pathForResource: #"Fav" ofType:#"plist"];
// Build the array from the plist ------>>>
NSDictionary *favs = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
Resepies = [favs objectForKey:#"Root"];
[Resepies addObject:addYourObjectHere];
//then add this array into dictonary ;
[favs setObject:Resepies forKey:#"Root"];
// now write dictionary to plist
[favs writeToFile:yourPlistName atomically:YES];
You can't modify files in the application bundle, which is what your code above is attempting to do.
If the file is supposed to be modifiable, you need to move it into the documents folder first (say, on first run) and then read / write to that one subsequently. There are plenty of questions dealing with how to do this, for example : create plist and copying plist to document directory

NSKeyedUnarchiver decodeObjectForKey returning null class

I have an archive which is stored in "Presidents.plist" file. It exist and I can locate it using pathForResource method. And also I do get the data using initWithContentsOfFile method of NSData to retrieve the data. The problem now is in this lines of code.
NSString *path = [[NSBundle mainBundle] pathForResource:#"Presidents"
ofType:#"plist"];
NSData *data;
NSKeyedUnarchiver *unarchiver;
data = [[NSData alloc] initWithContentsOfFile:path];
unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
id presidents = [unarchiver decodeObjectForKey:#"Presidents"];
For some reason it is returning a null class instead of my expected NSArray class. Can anyone tell me the reason this is happening and how can I solve this dilemma?
I'm getting the class like this...
NSLog(#"presidents class = %#", NSStringFromClass([presidents class]));
I had the same problem, Method 2 helped me.
Change the "BIDPresident" to the "President" in Presidents.plist using TextWrangler or try my file http://www.fileswap.com/dl/o29Sxm48g0/Presidents.plist.html
You can access the object by:
NSMutableDictionary dict = [NSKeyedUnarchiver unarchiveObjectWithFile:archieverPath];
archieverPath is the path of the plist.
and you can return the object by
return [dict objectForKey:key];
In more recent versions of iOS the root object of a pList must not be an array. I had this problem recently. Try using a dictionary instead.

Why redefine pListPath in didSelectRowAtIndexPath?

So I've read a ton of SO-questions about plists and how to save to them, and although I don't know, why no iPhone-Dev-Book I've seen so far covered this (they all used the tableView editing function), I managed to REALLY write to a plist by copying it to the documents folder like this:
pListPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
pListPath = [pListPath stringByAppendingPathComponent:#"piggyBanks.plist"];
NSLog(#"Path: %#", pListPath);
// if the file does not exist yet, create it, and copy the plist data into it, that can be found in the bundle
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:pListPath]) {
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"piggyBanks" ofType:#"plist"];
[fileManager copyItemAtPath:sourcePath toPath:pListPath error:nil];
}
// make the plist content available for usage
pListContent = [[NSMutableDictionary alloc] initWithContentsOfFile:pListPath];
NSLog(#"pListContent: %#", pListContent);
So far so good, but now, if I wanna change some plist value when a user taps on a tableViewCell (it's a custom one, if that's important), although pListPath, pListContent and others are properties, defined in .h and synthesized in .m, I have to redefine pListPath and pListContent inside didSelectRowAtIndexPath, to get the path to be known in that moment.
Could someone please tell me why? I mean, it's nice, that it works, but I'd like to know, why it has to be like that, or if I did a mistake somewhere else..
Thanks!
If plistPath is a string property of your class, you need to assign it as such:
if (!self.pListPath)
{
NSString *newPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
newPath = [newPath stringByAppendingPathComponent:#"piggyBanks.plist"];
self.pListPath = newPath;
}
Then afterwards, use self.pListPath instead of pListPath.
You are having to re-set it because at the moment, pListPath is being assigned to an autoreleased string which will have been removed by the time you need it again. Setting the property (assuming the property is retained or copied) will retain the string for you.
I googled for class variables in objective C, and found my way through various articles, till i found this blog/blogpost, which explains the self. and _underscore thing really well!
I now always declare my Ivars with an underscore, the properties without. Works out quite well. And to sum it up, why to ALWAYS use self.yourPropertiesName, you are calling a method (setter and getter)! And like any other method you are calling, you need to say, who is calling.
Hope this will help someone else too :)

can't read plist from resources

in my resources directory i have a file called lsf.plist
i want to load this file (dictionary) but i always get null as content of the file. i am using the following code. i've verified that the file is in the app after the build.
self.path = [[NSBundle mainBundle] pathForResource:#"lsf" ofType:#"plist"];
NSLog(self.path);
self.lsf = [NSMutableArray arrayWithContentsOfFile:path];
NSLog(#"%#",lsf);
The first log-output shows the path and the second one gives me null....
it would be great if you can help me to solve this issue!
Br,
martin
Is root of your plist array or dictionary?
Also you dont need to use self.
Heres an example from a project of mine:
NSString* path = [[NSBundle mainBundle] pathForResource:#"property" ofType:#"plist"];
NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:path];

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.