Can not read plist file? - objective-c

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];

Related

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>

Error writing to plist in documents directory

I use the following code to copy a Resources plist file into the documents directory:
BOOL success;
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"Test-Info.plist"];
success = [fileManager fileExistsAtPath:filePath];
if (!success) {
NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingFormat:#"Test-Info.plist"];
success = [fileManager copyItemAtPath:path toPath:filePath error:&error];
NSLog(#"Test-Info.plist successfully copied to DocumentsDirectory.");
}
I get the success message, which is great. I'm assuming it's been copied correctly into the documents folder.
However when I then try to read and write to the saved plist file it returns null:
Key entry in Test-Info.plist:
Key: EnableEverything
Type: Boolean
Value: YES
Write code:
NSString *adKey = #"EnableEverything";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
NSString *path = [documentsDirectoryPath stringByAppendingPathComponent:#"Test-Info.plist"];
NSMutableDictionary *plist = [NSDictionary dictionaryWithContentsOfFile: path];
NSString *enableEverything = [[plist valueForKey:adKey] stringValue];
NSLog(#"****** EXISTING: %# ******", enableEverything); // returns (null)
// Disable in plist.
[plist setValue:0 forKey:adKey]; // will this work?
[plist writeToFile:path atomically:YES]; // this doesn't throw an error?
NSString *enableEverything1 = [[plist valueForKey:adKey] stringValue];
NSLog(#"****** NOW: %# ******", enableEverything1); // returns (null)
Output:
****** EXISTING: (null) ******
****** NOW: (null) ******
My question is why are they (null) when they exist within the plist file?
You are trying to mutate an immutable object.
You need a NSMutableDictionary.
IE
NSMutableDictionary *plist = [[NSDictionary dictionaryWithContentsOfFile: path] mutableCopy];
Also check, if the plist object isnt nil, as any messages can be send to nil without raiing an error. this wouldnt fail, also nothing actually happens.
[plist setValue:0 forKey:adKey]; // will this work?
[plist writeToFile:path atomically:YES]; // this doesn't throw an error?
as the source path is nil, you are most like not copying the file during compilation bundling. drag it here:
Try this for nsbundle path for resource
NSString *path= [[NSBundle mainBundle] pathForResource:#"SportsLogo-Info" ofType:#"plist"];
Try allocating
NSMutableDictionary *plist = [[NSMutableDictionary alloc] initWithDictionary:[NSDictionary dictionaryWithContentsOfFile:path]];
Also check if the file has been copied or not. Go to Library=>Application Support=>iPhone Simulator=>folder named your version of simulator iOS=>Applications=>Find the right folder of your project=>Documents see if the plist file is there

Plist cannot be read ... What am I doing wrong?

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];
}
}

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");
}