iOS 9 Error write .plist - objective-c

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>

Related

Mac OSX How can I add plist to bundle and modify the plist

I have a plist and I copy the plist to my xcode project but it seems like the file is not in bundle:
NSDictionary *dict = [[NSBundle mainBundle] infoDictionary];
nslog (#"dict %#",dict);
but the file plist file is not showing. Question, how can I add the file to project in a way to see in the bundle? also any of you knows how can I modify the plist and save the changes?
I'll really appreciated your help
P.S. I'm using Xcode 5.
You can create a plist file in your bundle and modify its contents as:
NSString *bundlePath = [[NSBundle mainBundle]bundlePath]; //Path of your bundle
NSString *path = [bundlePath stringByAppendingPathComponent:#"MyPlist.plist"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableDictionary *data;
if ([fileManager fileExistsAtPath: path])
{
data = [[NSMutableDictionary alloc] initWithContentsOfFile: path]; // if file exist at path initialise your dictionary with its data
}
else
{
// If the file doesn’t exist, create an empty dictionary
data = [[NSMutableDictionary alloc] init];
}
//To insert the data into the plist
int value = 5;
[data setObject:[NSNumber numberWithInt:value] forKey:#"value"];
[data writeToFile: path atomically:YES];
[data release];
//To retrieve the data from the plist
NSMutableDictionary *savedData = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
int savedValue;
savedValue = [[savedData objectForKey:#"value"] intValue];
NSLog(#"%i",savedValue);
infoDictionary will return Info.plist file.
You should use pathForResource:ofType: method of NSBundle class.
NSString *commonDictionaryPath;
if (commonDictionaryPath = [[NSBundle mainBundle] pathForResource:#"CommonDictionary" ofType:#"plist"]) {
theDictionary = [[NSDictionary alloc] initWithContentsOfFile:commonDictionaryPath];
}
How can I add plist to bundle
Drag your plist to "Copy Bundle Resources" phase of your build target
modify the plist
Copy the plist to your app's Documents folder and modify it there.
this should work
NSString*pListDictPath = [[NSBundle mainBundle] pathForResource:#"yourPlistName" ofType:#"plist" inDirectory:#"YourDirectory"];
if()
{
NSDictionary *theDictionary = [[NSDictionary alloc] initWithContentsOfFile:pListDictPath ];
}

Objective-C: writing values to a specific index of an Array inside a .plist

I understand I can for instance write a value to a .plist file as such
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"stored" ofType:#"plist"];
NSString *comment = #"this is a comment";
[comment writeToFile:filePath atomically:YES];
But If i had for say an Array inside my .plist (gameArray) and I'd like to white comment into a particular index of my array i.e. gameArray[4] ; how would I do this ?
allow me to clarify
I have a plist: stored.plist
inside my plist there is an array gameArray
i would like to update specific indexes of gameArray inside the plist
is this possible ?
You cannot update and save data in application's main bundle instead you have to do in document directory or other directory like this:
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistFilePath = [documentsDirectory stringByAppendingPathComponent:#"stored.plist"];
if([[NSFileManager defaultManager] fileExistsAtPAth:plistFilePath])
{//already exits
NSMutableArray *data = [NSMutableArray arrayWithContentsOfFile:plistFilePath];
//update your array here
NSString *comment = #"this is a comment";
[data replaceObjectAtIndex:4 withObject:comment];
//write file here
[data writeToFile:plistFilePath atomically:YES];
}
else{ //firstly take content from plist and then write file document directory
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"stored" ofType:#"plist"];
NSMutableArray *data = [NSMutableArray arrayWithContentsOfFile:plistPath];
//update your array here
NSString *comment = #"this is a comment";
[data replaceObjectAtIndex:4 withObject:comment];
//write file here
[data writeToFile:plistFilePath atomically:YES];
}
Assuming the contents of 'stored.plist' is an array, you need to instantiate a mutable array from the path:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"stored" ofType:#"plist"];
NSMutableArray *array = [NSMutableArray arrayWithContentsOfFile:filePath];
NSString *comment = #"this is a comment";
// inserting a new object:
[array insertObject:comment atIndex:4];
// replacing an existing object:
// classic obj-c syntax
[array replaceObjectAtIndex:4 withObject:4];
// obj-c literal syntax:
array[4] = comment;
// Cannot save to plist inside your document bundle.
// Save a copy inside ~/Library/Application Support
NSURL *documentsURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask] objectAtIndex:0];
NSURL *arrayURL = [documentsURL URLByAppendingPathComponent:[filePath lastPathComponent]];
[array writeToURL:arrayURL atomically:NO];

Create plist file via code

I want to create a plist file like this:
in code, and then it will be in the Caches folder.
I already know how to fetch the data.
You can do it like this:
//Create a Mutant Dictionary
NSMutableDictionary *theMutantDict = [[NSMutableDictionary alloc] init];
//Fill it with data
[theMutantDict setObject:#"John" forKey:#"Name"];
[theMutantDict setObject:#"Doe" forKey:#"Lastname"];
//Then search for cache dir
NSString *libraryDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
NSUserDomainMask, YES) objectAtIndex:0];
NSString *cacheDir = [libraryDir stringByAppendingPathComponent:#"Caches"];
//Then write the file
NSString *filePath = [cacheDir stringByAppendingString:#"/TheFile.plist"];
[theMutantDict writeToFile:filePath atomically:YES];
Just use the writeToFile-method of NSArray to store the array in a plist and arrayWithContentsOfFile to load it.
[self.array writeToFile:path atomically:YES];
self.array = [[NSArray arrayWithContentsOfFile:path];
// or in case you need to add/remove objects (NSMutableArray):
self.array = [[[NSArray arrayWithContentsOfFile:path] mutableCopy] autorelease];
If you got your data stored in an NSArray it's as easy as this:
// filling array with data ...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [paths objectAtIndex:0];
NSString *plistPath = [cachePath stringByAppendingPathComponent:#"my_nsarray_data.plist"];
[klasserArray writeToFile:plistPath atomically:YES];
// other stuff ...

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