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

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

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>

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

Overwrite with remote .plist a local .plist file

My application loads a local list.plist file at launch.
Then it has a refreshTable button which fetch a remote version of the .plist file from my website.
App Launch
local list.plist loads
user hits refreshList button
local list.plist is overwritten by remote list.plist
local list.plist updated until remote list.plist updates again
Method to initialize data:
//Remote data
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
//Local data
NSString *localPath = [[NSBundle mainBundle] pathForResource:#"list" ofType:#"plist"];
localList = [[NSMutableArray alloc] initWithContentsOfFile:localPath];
NSSortDescriptor *localDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
localSortedList = [[localList sortedArrayUsingDescriptors:[NSArray arrayWithObject:localDescriptor]] retain];
This is the method to refresh:
- (void) refreshTable:(id)sender
{
//Remote .plist
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
[self.tableView reloadData];
//now write remote plist to local plist
}
After i downloaded the remote plist how can i write over the local plist?
I was thinking to empty the local array containing the local plist and fill it with the remote array and i did it this way:
I solved in the way i thought:
//Remote .plist
list = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://phillipapps.com/mntlion/list.plist"]];
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)] autorelease];
sortedList = [[list sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
NSLog(#"list: %#",list);
[localList removeAllObjects];
[localList addObjectsFromArray:list];
localSortedList = [[localList sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]] retain];
NSLog(#"locallist: %#",localList);
[self.tableView reloadData];
It works, but how can i write over localList with the contents of list?
so … after a view hours in chat we got the problem solved.
- (NSArray*)readPlist
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:#"localFile.plist"];
NSFileManager *fMgr = [NSFileManager defaultManager];
if (![fMgr fileExistsAtPath:plistPath]) {
plistPath = [[NSBundle mainBundle] pathForResource:#"template" ofType:#"plist"];
}
return [NSArray arrayWithContentsOfFile:plistPath];
}
- (void)writePlist:(NSArray*)arr
{
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[documentPaths lastObject] stringByAppendingPathComponent:#"localFile.plist"];
NSFileManager *fMgr = [NSFileManager defaultManager];
if (![fMgr fileExistsAtPath:plistPath])
[fMgr removeItemAtPath:plistPath error:nil];
[arr writeToFile:plistPath atomically:YES];
}
initializing the ivar:
self.plistArray = [self readPlist];
and after loading the new plist from the server you have to call this code:
self.plistArray = [NSArray arrayWithContentsOfURL:[NSURL URLWithString:#"http://mywebsite.com/list.plist"]];
[self writePlist:plistArray]; // e.g. for caching
[self.tableView reloadData];
I do almost the exact thing you're looking for in an application of mine. You can't write to the NSBundle so the steps are something like this:
Try to load plist from cache directory, if it succeeds go to 3.
Load plist from bundle
Check if loaded plist is up to date (or, trigger further steps by the press of a button)
Download new plist
Save to cache directory
The code looks something like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cache = [paths objectAtIndex:0];
ratios = [NSDictionary dictionaryWithContentsOfFile:[cache stringByAppendingPathComponent:#"devices.plist"]];
if (ratios == nil) {
ratios = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"devices" ofType:#"plist"]];
}
NSString *device = [[UIDevice currentDevice] machine];
NSDictionary *d = [ratios objectForKey:device];
if (d!=nil) {
pixelInchRatio = [[d objectForKey:#"pixelInchRatio"] doubleValue];
bezelWidth = [[d objectForKey:#"bezelWidth"] doubleValue];
bezelHeight = [[d objectForKey:#"bezelHeight"] doubleValue];
} else if (fetch) {
[[[[RulerDimensionDownload alloc] init] autorelease] startDownload];
}
Then in the downloader it saves like so:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cache = [paths objectAtIndex:0];
[[NSFileManager defaultManager] createDirectoryAtPath:cache withIntermediateDirectories:YES attributes:nil error:nil];
[ratios writeToFile:[cache stringByAppendingPathComponent:#"devices.plist"] atomically:YES];
Some explanations:
The first few lines in each sample, the paths and cache definition, simply get the location of the cache directory for the application. I use this to store the most up-to-date version I'm my plist.
So, in the loading code, I first try to load the plist from the cache directory. If this fails (ratios is null) I then load it from my application bundle (this is the version of the plist that I ship with the app).
After that, I check to see if the plist has the information needed. (the plist has a definition for each device type. If the device isn't in the plist then I know I need to try to update the plist)
If the plist is out of date I start the download using a class I wrote: RulerDimensionDownload. Once it completes the download I save the file into the cache directory. Then, next time the plist needs to be loaded it will be loaded first and the shipped plist will never be looked at. (I also send a notification with the new plist)

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

iphone read from file

i create a view based application , in this project i want read data from .plist file.
how it is possible,
Pleas help me ?
NSString *path = [[NSBundle mainBundle] pathForResource:#"plistfilename" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:#"%#", path]];
NSString *body = [dict objectForKey:#"Keyname"];
with the use of this anyone can read data from plist file.
If you are sure the .plist file is a dictionary at root level,
return [NSDictionary dictionaryWithContentsOfFile:#"path/to/your.plist"];
otherwise,
NSData* plist_data = [NSData dataWithContentsOfFile:#"path/to/your.plist"];
return [NSPropertyListSerialization propertyListFromData:plist_data mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:NULL];