Plist cannot be read ... What am I doing wrong? - objective-c

I have got a plist in my Resources folder called "levelconfig.plist" and I want to read something out of it.
I did the following :
-(NSString *) dataFilePath
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
return [documentDirectory stringByAppendingPathComponent:#"levelconfig.plist"];
}
-(void) readPlist{
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
NSLog(#"%#",array);
NSLog(#"%#", filePath);
}
}
And in the ccTouchesBegan method I call :
[self readPlist];
My plist contains an array, that should be displayed right ? Is it a good idea to store level data in a .plist file ?
plist file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Root</key>
<array>
<string>sunday</string>
<string>monday</string>
<integer>44</integer>
</array>
</dict>
</plist>

You must first read the dictionary as specified in your plist. For example:
NSString *mainPath = [[NSBundle mainBundle] bundlePath];
NSString *itemPositionPlistLocation = [mainPath stringByAppendingPathComponent:#"test.plist"];
NSDictionary * itemPositions = [[NSDictionary alloc] initWithContentsOfFile:itemPositionPlistLocation];
NSArray * items = [itemPositions objectForKey:#"Root"];
NSLog(#"%#", items);
I'm not sure what you are doing with your other code but two lines suffice to load the file. Please excuse the variable names; I quickly adapted this from my current project. Also, make sure you release the Array and Dictionary in dealloc or wherever appropriate.

Are you sure it's in your resources folder? In that case you aren't building the path properly. You will probably want to use [NSBundle pathForResource:] (docs)

Your pList file is a Dictionary that has an array in the Root key and you are reading it in to an Array.
-(void) readPlist{
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:filePath];
NSArray *array = [[NSArray alloc]initWithArray:[dict objectForKey:#"Root"]];
NSLog(#"%#",array);
NSLog(#"%#", filePath);
[dict release];
[array release];
}
}

Related

how to display values on labels from plist. objective-c

i have the plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>Daniel</string>
<key>Description</key>
<string>Bad boy</string>
</dict>
<dict>
<key>name</key>
<string>Mary</string>
<key>description</key>
<string>Good girl</string>
</dict>
</array>
</plist>
i want to display on my label's values name and description depending of name:
NSString *path = [[NSBundle mainBundle] pathForResource:#"PropList" ofType:#"plist"];
ComplexArray = [NSArray arrayWithContentsOfFile:path];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
for (int i = 0; i < [ComplexArray count]; i++) {
ThirdViewController *item = [ComplexArray objectAtIndex:i];
if ([item.name isEqualToString: #"Mary"]) {
_nameLabel.text = [dict objectForKey:#"name"];
_descriptionLabel.text = [dict objectForKey:#"description"];
}
}
And why i can't do like this (i did this when i have no plist, but now this return errors):
NSString *path = [[NSBundle mainBundle] pathForResource:#"PropList" ofType:#"plist"];
ComplexArray = [NSArray arrayWithContentsOfFile:path];
for (int i = 0; i < [ComplexArray count]; i++) {
ThirdViewController *item = [ComplexArray objectAtIndex:i];
if ([item.name isEqualToString: #"Mary"]) {
_nameLabel.text=item.name;
_descriptionLabel.text=item.description;
}
}
Again, you pretty much had it right already.
NSString *path = [[NSBundle mainBundle] pathForResource:#"PropList" ofType:#"plist"];
ComplexArray = [NSArray arrayWithContentsOfFile:path];
for (NSDictionary *dict in ComplexArray) {
if ([dict[#"name"] isEqualToString:#"Mary"]) {
_nameLabel.text = dict[#"name"];
_descriptionLabel.text = dict[#"description"];
break;
}
}
Perform following steps:
Get the plist data in a dictionary
NSString *plistPath=[[NSBundle mainBundle] pathForResource:#"NameOfPlistFile" ofType:#"plist"];
NSDictionary *bundleDictionary=[NSDictionary dictionaryWithContentsOfFile:plistPath];
Get the Value with respect to Key
NSString *nameString = [bundleDictionary valueForKey:kCustomURLScheme];
Hope this helps!
Try This code it Must work perfect !
// Read plist from bundle and get Root Dictionary out of it
NSDictionary *dictRoot = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"PropList" ofType:#"plist"]];
// Your dictionary contains an array of dictionary
// Now pull an Array out of it.
NSArray *array = [dictionary objectForKey:#"keyarray"];
// Now a loop through Array to fetch single Item
for (NSDictionary *dict in array) {
if ([[dict objectForKey:#"name"] isEqualToString:#"Mary"])
{
// Do stuff...
NSString *name= [dict objectForKey:#"name"];
NSString *description= [dict objectForKey:#"Description"];
}
}
you need to add a key befor the array .
<key>keyarray</key>

iOS 9 Error write .plist

My App errors after update to iOS 9. Can't write .plist file in project.
-(BOOL)writeDictionaryToPlist:(NSDictionary*)plistDict {
NSString *path = [[NSBundle mainBundle] pathForResource:#"History" ofType:#"plist"];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValuesForKeysWithDictionary:plistDict];
NSDictionary *saveDict = [NSDictionary dictionaryWithDictionary:dict];
BOOL result = [saveDict writeToFile:path atomically:YES];
return result;
}
result is NO.
But iOS 7 and iOS 8 is works fine.
How I can fix it ?
Use dictionaryWithContentsOfFile: to write to dictionary from plist
NSString *path = [[NSBundle mainBundle] pathForResource:#"History" ofType:#"plist"];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
BOOL result = [dict writeToFile:path atomically:YES];
NOTE since plist is the app resource you cant write to that file, hence create a plist file in your documents directory and write to that file.
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
path = [path stringByAppendingString:#"/History.plist"];
BOOL result = [dict writeToFile:path atomically:YES];
Retrieve the data from plist
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
UPDATE
Add NSAppTransportSecurity as a dictionary and the first child should be a bool named NSAllowsArbitraryLoads set to YES.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

Can not read plist file?

I have a annoying error which came suddenly. I wanted to read a .plist file. However it is currently impossible. It worked yesterday, even 3 hours ago and then my app crashed on the simulator and on the device. I have listened to this tutorial (twice) (and others):
https://www.youtube.com/watch?v=3Oy-evy2xD8
Googled many stackoverflow solutions (beside these two...):
Plist cannot be read ... What am I doing wrong?
Can't read from plist
And still I did not get one step closer to a soultion.
NSError *error;
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [path objectAtIndex:0];
documentDirectory = [documentDirectory stringByAppendingPathComponent:#"testPlist.plist"];
NSLog(#" documentDirectory: - %# ",documentDirectory);
if ([[NSFileManager defaultManager] fileExistsAtPath:documentDirectory])
{
NSLog(#" The file exits! ! !");
}
else
{
NSLog(#" The file DOES NOT exits !!!");
}
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath: documentDirectory]) {
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"testPlist" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath:documentDirectory error:&error];
NSLog(#"plist is copied to Directory");
}
NSDictionary * plistDictionary = [[NSDictionary alloc] initWithContentsOfFile:documentDirectory];
NSMutableDictionary * plistMutableDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:documentDirectory];
NSArray *items = [plistDictionary objectForKey:#"Root"];
//NSMutableArray *itemsFromMutableDict = [[NSMutableArray alloc] init];
//[itemsFromMutableDict addObject:[plistDictionary objectForKey:#"Root"]];
NSLog(#" Path : %# ",documentDirectory);
NSLog(#" Items in array = %#", items);
NSLog(#" array count = %i", [items count]);
NSLog(#" Why is this %# ?",[plistDictionary objectForKey:#"Root"]);
The output is :
2014-06-12 11:24:25.894 PlistTestingProject[1879:60b] All paths : /Users/webbite_mladen/Library/Application Support/iPhone Simulator/7.1/Applications/A1A7D9E3-BFDE-4C52-8C5F-28F0D88D6F5F/Documents
2014-06-12 11:24:25.896 PlistTestingProject[1879:60b] documentDirectory: - /Users/webbite_mladen/Library/Application Support/iPhone Simulator/7.1/Applications/A1A7D9E3-BFDE-4C52-8C5F-28F0D88D6F5F/Documents/testPlist.plist
2014-06-12 11:24:25.897 PlistTestingProject[1879:60b] The file exits! ! !
2014-06-12 11:24:25.897 PlistTestingProject[1879:60b] Path : /Users/webbite_mladen/Library/Application Support/iPhone Simulator/7.1/Applications/A1A7D9E3-BFDE-4C52-8C5F-28F0D88D6F5F/Documents/testPlist.plist
2014-06-12 11:24:25.898 PlistTestingProject[1879:60b] Items in array = (null)
2014-06-12 11:24:25.898 PlistTestingProject[1879:60b] array count = 0
2014-06-12 11:24:25.899 PlistTestingProject[1879:60b] Why is this (null) ?
It seems that I cannot access the plist file.
The plist file content:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Root</key>
<array>
<string>sunday</string>
<string>monday</string>
<integer>44</integer>
</array>
</dict>
</plist>
Thanks :).
Try using this..
NSDictionary *dictRoot = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"file_name" ofType:#"plist"]];
NSArray *arrRoot = [NSArray arrayWithArray:[dictRoot objectForKey:#"Root"]];
The most simple solution finally worked:
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"myPlistFile"
ofType:#"plist"];
NSMutableArray *myArray = [NSMutableArray arrayWithContentsOfFile:plistPath];

access to plist in app bundle returns null

I'm using a piece of code I've used before with success to load a plist into an array:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"species_names" ofType:#"plist"];
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
The initWithContentsOf File is failing (array is null, suggesting it can't find the plist in the app bundle).
Under the iPhone simulator I've checked that the path created by the first line points to the app file (it does), and used the Finder context menu "Show package contants" to prove to myself that "species_name.plist" is actually in the bundle--with a length that suggests it contains stuff, so it should work (and has in other iOS apps I've written). Suggestions most welcome...
[env Xcode 4.2 beta, iOS 4.3.2].
You should use initWithContentsOfFile: method of NSDictionary instance, not NSArray.
Here is sample:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"species_names" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:filePath];
NSArray *array = [NSArray arrayWithArray:[dict objectForKey:#"Root"]];
Or this:
NSString *errorDesc = nil;
NSPropertyListFormat format;
NSString *path = [[NSBundle mainBundle] pathForResource:#"startups" ofType:#"plist"];
NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:path];
NSDictionary *temp = (NSDictionary *)[NSPropertyListSerialization
propertyListFromData:plistXML
mutabilityOption:NSPropertyListMutableContainersAndLeaves
format:&format
errorDescription:&errorDesc];
NSArray *array = [NSArray arrayWithArray:[temp objectForKey:#"Root"]];
EDIT
You can use initWithContentsOfFile: method of NSArray with file created with writeToFile:atomically: method of NSArray. Plist created with writeToFile:atomically: has this stucture:
<plist version="1.0">
<array>
...Content...
</array>
</plist>
And Plist created in XCode has this stucture:
<plist version="1.0">
<dict>
...Content...
</dict>
</plist>
Thats why initWithContentsOfFile: method of NSArray dosnt work.
plist of this type:
OR (basically both are same)
Can be read like this:
NSString *file = [[NSBundle mainBundle] pathForResource:#"appFeatures" ofType:#"plist"];
NSArray *_arrFeats = [NSArray arrayWithContentsOfFile:file];
NSLog(#"%d", _arrFeats.count);
Where appFeatures is name of the plist.
(iOS 6.1)
Try this simple metod:
- (void)viewDidLoad
{
[super viewDidLoad];
[self plistData];
}
- (void)plistData
{
NSString *file = [[NSBundle mainBundle] pathForResource:#"appFeatures" ofType:#"plist"];
NSArray *messages = [NSArray arrayWithContentsOfFile:file];
NSLog(#"%d", messages.count);
for (int i=0; i<messages.count; i++)
{
NSString *data = [messages objectAtIndex:i];
NSLog(#"\n Data = %#",data);
}
}

Plist Array to NSDictionary

I have a plist:
<plist version="1.0">
<array>
<dict>
<key>name</key>
<string>Alabama</string>
<key>abreviation</key>
<string>AL</string>
<key>date</key>
<string>1819</string>
<key>population</key>
<string>4,627,851</string>
<key>capital</key>
<string>Montgomery</string>
<key>largestCity</key>
<string>Birmingham</string>
</dict>
<dict>
<key>name</key>
<string>Alaska</string>
<key>abreviation</key>
<string>AK</string>
<key>date</key>
<string>1959</string>
<key>population</key>
<string>683,478</string>
<key>capital</key>
<string>Juneau</string>
<key>largestCity</key>
<string>Anchorage</string>
</dict>
...
</array>
</plist>
I am trying to load it into an NSDictionary like this:
NSString *path = [[NSBundle mainBundle] pathForResource:#"stateInfo" ofType:#"plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:path]) {
NSLog(#"The file exists");
} else {
NSLog(#"The file does not exist");
}
NSMutableDictionary *myDic = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
//NSDictionary *myDic = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(#"The count: %i", [myDic count]);
NSArray *thisArray = [[NSArray alloc] initWithContentsOfFile:path];
NSLog(#"The array count: %i", [thisArray count]);
I always get an array count of 50 but a dictionary count of zero. So I tried looping through the array and adding it to the dictionary:
NSDictionary *eachState;
for (eachState in thisArray) {
State *thisState = [[State alloc] initWithDictionary:eachState];
[myDic setObject:thisState forKey:thisState.name];
}
But the loop is throwing an exception:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '*** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
State is a class with properties matching my plist. What am I doing wrong? I see all kinds of related questions out here but I can't get it.
The two problems:
Loading the plist into an NSDictionary:
This is a simple problem, which it seems you have already figured out. The global object in your plist is an array, not a dict, so when you load it into the dictionary, it doesn't know what to do (incompatable types), so you're getting an empty dictionary.
Looping through the array of dictionaries:
From the Exception you're getting, you are calling 'setObject:forKey:' on the dictionary, which is initialized as an NSDictionary, not an NSMutableDictionary. The pointer is typed as NSMutableDictionary, but not the actual in memory object. You need to change your line from.
NSMutableDictionary *myDic = [[NSDictionary alloc] initWithContentsOfFile:path];
to
NSMutableDictionary *myDic = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
and actually, since loading the dictionary from the file gives you an empty dictionary, you are wasting cycles trying to load it from the file, and should just create a new one:
NSMutableDictionary *myDic = [[NSMutableDictionary alloc] init];
A more flexible way to load plists into memory, that also allows you to create mutable plists:
NSData* data = [NSData dataWithContentsOfFile:path];
NSMutableArray* plist = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NSPropertyListXMLFormat_v1_0
errorDescription:NULL];
Thus your code could be implemented as:
NSString *path = [[NSBundle mainBundle] pathForResource:#"stateInfo" ofType:#"plist"];
NSData* data = [NSData dataWithContentsOfFile:path];
NSMutableArray* array = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NSPropertyListXMLFormat_v1_0
errorDescription:NULL];
if (array) {
NSMutableDictionary* myDict = [NSMutableDictionary dictionaryWithCapacity:[array count]];
for (NSDictionary* dict in array) {
State* state = [[State alloc] initWithDictionary:dict];
[myDict setObject:state forKey:state.name;
[state release];
}
NSLog(#"The count: %i", [myDic count]);
} else {
NSLog(#"Plist does not exist");
}