Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 01-09-2011, 05:47 PM   #1 (permalink)
Registered Member
 
Join Date: Jul 2009
Location: North America
Posts: 53
shimmy is on a distinguished road
Default plist resource file in xcode is not modified when calling writeToFile

Hi y'all

This question is probably more related to a confusion with how to use xcode, but I'm not sure.

So I have a plist file in xcode which I added as a resource. It contains an array of dictionaries. data.plist, for simplicity.

I load the data from this file in my main view controller's viewDidLoad function, no problems there. From there, I can see clearly that the file
(used a call like [[NSBundle mainBundle] pathForResource: @"data" ofType: @"plist"] is loaded from the local directory of the XCode project, i.e. the same folder as the xcodeproj file for my project. However, later on in the app lifecycle, in the app delegate's applicationDidEnterBackground function, I want to save any changes to this plist file. However, when I call pathForResource, it's clear that the file that is being modified is only the plist file inside the builded version of the app in the following path
Users/My Username/Library/Application Support/iPhone Simulator/4.2/Applications/C8F45V22-26C2-5C7G-A105-E038C25F4255/MyApp.app/data.plist

And this file is only accessible through the finder by opening the contents of the .app file. So my question is, how can I get it so that when I modify/over write the contents of that plist file, it will show up in the file that I have in my xcode window under "Resources"? I've looked around extensively to see if other people have had the same issue, but surprisingly I have not been able to find anything (probably not using the right keywords).


Thanks for your help.

Anyhow
shimmy is offline   Reply With Quote
Old 01-09-2011, 07:57 PM   #2 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by shimmy View Post
Hi y'all

This question is probably more related to a confusion with how to use xcode, but I'm not sure.

So I have a plist file in xcode which I added as a resource. It contains an array of dictionaries. data.plist, for simplicity.

I load the data from this file in my main view controller's viewDidLoad function, no problems there. From there, I can see clearly that the file
(used a call like [[NSBundle mainBundle] pathForResource: @"data" ofType: @"plist"] is loaded from the local directory of the XCode project, i.e. the same folder as the xcodeproj file for my project. However, later on in the app lifecycle, in the app delegate's applicationDidEnterBackground function, I want to save any changes to this plist file. However, when I call pathForResource, it's clear that the file that is being modified is only the plist file inside the builded version of the app in the following path
Users/My Username/Library/Application Support/iPhone Simulator/4.2/Applications/C8F45V22-26C2-5C7G-A105-E038C25F4255/MyApp.app/data.plist

And this file is only accessible through the finder by opening the contents of the .app file. So my question is, how can I get it so that when I modify/over write the contents of that plist file, it will show up in the file that I have in my xcode window under "Resources"? I've looked around extensively to see if other people have had the same issue, but surprisingly I have not been able to find anything (probably not using the right keywords).


Thanks for your help.

Anyhow

The short answer is, you don't, and you shouldn't.

It would not make sense to have a running app change the XCode resources directory that is used to build that app. If you did that, you wouldn't be able to build the original app again.

Furthermore, an app's resources are ALSO read-only. On an iOS device, writing a file into the application's bundle will fail. On the simulator it works, but is a very bad idea. Your app should treat it's bundle as read-only even on the simulator.

If you're trying to write some one-time code that builds things like plists that you then want to put into your app, have your app write the files into the documents directory, then open the simulator's documents directory in the finder and manually copy the files into the project's resources directory.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 01-09-2011, 08:17 PM   #3 (permalink)
Registered Member
 
Join Date: Jul 2009
Location: North America
Posts: 53
shimmy is on a distinguished road
Default ok...so...?

Ok, so then how do I save data changes made in my app? ie. you edit certain things that were loaded from the original plist (eg edit/delete an item in a list) and want to replace them when the application closes. This is something that would occur frequently in almost any application. What is usually done? You said your suggestion was only if I wanted to do a one-time job... but I don't see any other option than loading from resources and loading from "documents"

I thought a "resource" was just like any file.


thanks
shimmy is offline   Reply With Quote
Old 01-11-2011, 04:52 PM   #4 (permalink)
Registered Member
 
Join Date: Jul 2009
Location: North America
Posts: 53
shimmy is on a distinguished road
Default

So do you have a response to my question?

What I don't understand is the method you describe is essentially the only other way to do it.

I see that you cannot modify the app bundle, so what you have to do is build the file as part of the app bundle and then copy it to the App's Document's directory at run-time. However, your response makes it sound like this is only for one time-use / testing purposes.

Last edited by shimmy; 01-11-2011 at 05:02 PM. Reason: added detail
shimmy is offline   Reply With Quote
Old 01-11-2011, 05:10 PM   #5 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by shimmy View Post
So do you have a response to my question?
On launch, check for the plist file in your app's documents directory.

If it doesn't exist, copy it from your app bundle to the documents directory.

Always open, read and write the plist from the documents directory.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 01-11-2011, 05:50 PM   #6 (permalink)
Registered Member
 
Join Date: Jul 2009
Location: North America
Posts: 53
shimmy is on a distinguished road
Default

And if I want to see dynamic changes to the plist file I should just open the one in the documents folder?
shimmy is offline   Reply With Quote
Old 01-11-2011, 06:26 PM   #7 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by shimmy View Post
And if I want to see dynamic changes to the plist file I should just open the one in the documents folder?
To quote my previous post:

"Always open, read and write the plist from the documents directory."
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Old 01-11-2011, 06:29 PM   #8 (permalink)
Registered Member
 
Join Date: Jul 2009
Location: North America
Posts: 53
shimmy is on a distinguished road
Default

Sorry, I meant in XCode / external to the application for debugging purposes

Anyways, to round off this discussion I have posted some of the code for loading / checking / copying the file, and this is basically copied straight from the apple documentation on plist programming anyhow.

I put the code in the app delegate, applicationDidFinishLaunching. Other code for reading/writing the data is elsewhere.


NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDire ctory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* dataPath = [documentsDirectory stringByAppendingPathComponent:@"Data.plist"];

/*because data stored in app bundle cannot be modified, if there is no data file in the documents directory, copy the one
* saved in the app bundle*/
if ( ![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
NSString* resourceaPath = [[NSBundle mainBundle] pathForResource:@"patientsDictionaries" ofType:@"plist"];
[[NSFileManager defaultManager] copyItemAtPath:resourceaPath toPath:dataPath error:NULL];
}

thanks for your assistance.

Last edited by shimmy; 01-11-2011 at 06:46 PM. Reason: more details
shimmy is offline   Reply With Quote
Old 02-24-2011, 04:13 AM   #9 (permalink)
Registered Member
 
Join Date: Feb 2011
Posts: 4
prasannamsv is on a distinguished road
Default how to update new plist files within xcode

Hi All,
I'm new to iPhone Development. Im getting a plist from a url. Is there any way to store or update the plist file within my application bundle using xcode or some other way




Quote:
Originally Posted by shimmy View Post
Sorry, I meant in XCode / external to the
application for debugging purposes

Anyways, to round off this discussion I have posted some of the code for loading / checking / copying the file, and this is basically copied straight from the apple documentation on plist programming anyhow.

I put the code in the app delegate, applicationDidFinishLaunching. Other code for reading/writing the data is elsewhere.


NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDire ctory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* dataPath = [documentsDirectory stringByAppendingPathComponent:@"Data.plist"];

/*because data stored in app bundle cannot be modified, if there is no data file in the documents directory, copy the one
* saved in the app bundle*/
if ( ![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
NSString* resourceaPath = [[NSBundle mainBundle] pathForResource:@"patientsDictionaries" ofType:@"plist"];
[[NSFileManager defaultManager] copyItemAtPath:resourceaPath toPath:dataPath error:NULL];
}

thanks for your assistance.
prasannamsv is offline   Reply With Quote
Old 02-24-2011, 04:16 AM   #10 (permalink)
Registered Member
 
Join Date: Feb 2011
Posts: 4
prasannamsv is on a distinguished road
Default how to update new plist files within xcode

Hi All,
I'm new to iPhone Development. Im getting a plist from a url. Is there any way to store or update the plist file within my application bundle using xcode or some other way... Any help please


Quote:
Originally Posted by Duncan C View Post
To quote my previous post:

"Always open, read and write the plist from the documents directory."
prasannamsv is offline   Reply With Quote
Old 02-24-2011, 04:25 AM   #11 (permalink)
Registered Member
 
Join Date: Oct 2009
Location: Amsterdam, The Netherlands
Posts: 782
TUX2K is on a distinguished road
Default

You can't modify the applications bundle when the app installed on the phone.
Just use the code above to save the plit file to the document directory, you can do this even if you download the file of the net.
__________________
If my answer helped you, you might want to help me.
Make a donation via PayPal.
TUX2K is offline   Reply With Quote
Old 03-04-2011, 03:20 AM   #12 (permalink)
Registered Member
 
Join Date: Mar 2011
Posts: 1
glorytech is on a distinguished road
Default Cannot copy file in UIViewController

Quote:
Originally Posted by shimmy View Post
Sorry, I meant in XCode / external to the application for debugging purposes

Anyways, to round off this discussion I have posted some of the code for loading / checking / copying the file, and this is basically copied straight from the apple documentation on plist programming anyhow.

I put the code in the app delegate, applicationDidFinishLaunching. Other code for reading/writing the data is elsewhere.


NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDire ctory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* dataPath = [documentsDirectory stringByAppendingPathComponent:@"Data.plist"];

/*because data stored in app bundle cannot be modified, if there is no data file in the documents directory, copy the one
* saved in the app bundle*/
if ( ![[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
NSString* resourceaPath = [[NSBundle mainBundle] pathForResource:@"patientsDictionaries" ofType:@"plist"];
[[NSFileManager defaultManager] copyItemAtPath:resourceaPath toPath:dataPath error:NULL];
}

thanks for your assistance.

HI, I copied the above code into "ViewDidLoad" function of a view-based project, it didn't work . The error said that the resourceaPath is nil.
However, when I copied the above code into "ViewDidLoad" function of a Navigation-based project , it works .
The difference between these 2 types of project is the UIViewController and UITableViewController classes. Any one know how to fix this problem in view-based project (i.e. in UIViewController)?

Thanks
glorytech is offline   Reply With Quote
Old 04-20-2011, 04:06 PM   #13 (permalink)
Registered Member
 
Join Date: Apr 2011
Posts: 1
Vanessa is on a distinguished road
Default

soo?? I'm still confused. the plist can not being modified. But can i do that using core data?. My information will display information i as a developer send so i dont need the user add/delete any row. it will be just me very frequently..
what should i use.. it is driving me crazy. I appreciate your help.
Thank you!
Vanessa is offline   Reply With Quote
Old 05-03-2011, 02:01 PM   #14 (permalink)
Registered Member
 
Join Date: May 2011
Posts: 1
dderuntz is on a distinguished road
Default Plist updating... quicky style.

Quote:
Originally Posted by Vanessa View Post
soo?? I'm still confused. the plist can not being modified. But can i do that using core data?. My information will display information i as a developer send so i dont need the user add/delete any row. it will be just me very frequently..
what should i use.. it is driving me crazy. I appreciate your help.
Thank you!
Test run the app.
Open the IOS Simulator menu.
Reset Content and Settings...

If you are using code to read/write .plist it won't bother updating it if it already sees on in that app's bundle. You would have to do this every time you update your plist in xcode.
dderuntz is offline   Reply With Quote
Old 04-26-2012, 02:35 PM   #15 (permalink)
Registered Member
 
Join Date: Apr 2012
Posts: 10
xcoder.ios is on a distinguished road
Default

Hi guys, I'm new to Iphone development.
I'm having problems with saving data like level scores in plist.
As I saw from the discussion that the copying/checking of the plist file code is written in the applicationDidFinishLaunching method.
My question is, where exactly do I write the code for reading and writing data???
I'm confused because reading and writing data includes code like :

NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];

It includes allocation. So if I want to write the score in plist after every level and read after every level. Then there will be too many allocations. So where exactly do I put this code. Also how do I read the contents of the whole plist file at once in a NSMutableDictionary???
Plz help!!!
xcoder.ios is offline   Reply With Quote
Old 04-26-2012, 02:50 PM   #16 (permalink)
Registered Member
 
Join Date: Jul 2009
Location: North America
Posts: 53
shimmy is on a distinguished road
Default

Quote:
Originally Posted by xcoder.ios View Post
Hi guys, I'm new to Iphone development.
I'm having problems with saving data like level scores in plist.
As I saw from the discussion that the copying/checking of the plist file code is written in the applicationDidFinishLaunching method.
My question is, where exactly do I write the code for reading and writing data???
I'm confused because reading and writing data includes code like :

NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];

It includes allocation. So if I want to write the score in plist after every level and read after every level. Then there will be too many allocations. So where exactly do I put this code. Also how do I read the contents of the whole plist file at once in a NSMutableDictionary???
Plz help!!!
Your question is a bit vague, but I'll try to answer anyway.
Reading data can also be done through [NSMutableDictionary dictionaryWithContentsOfFile:], although that's just a semantic difference, especially if you're using ARC.

You write a dictionary, say dic, to file with:
[dic writeToFile: path];

This overwrites what is stored at the file.

You really don't need to worry about allocating memory as you can just store the scores as a member of the class, and update it from the file each time you want to. You can define methods that store/retrieve the plist and overwrite your member variable with the data.

Check the NSDictionary/NSMutableDictionary documentation references for methods that might be useful for you.

There might be better ways to store/retrieve information depending on the context (such as CoreData) but plist is probably easiest for a beginner.
shimmy is offline   Reply With Quote
Old 04-26-2012, 10:46 PM   #17 (permalink)
Registered Member
 
Join Date: Apr 2012
Posts: 10
xcoder.ios is on a distinguished road
Default

sorry for the vague question.

for Reading :

NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile: path];

//load from savedStock example int value
int value;
value = [[savedStock objectForKey:@"value"] intValue];

[savedStock release];

for Writing :

NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];

//here add elements to data file and write data to file
int value = 5;

[data setObject:[NSNumber numberWithInt:value] forKey:@”value”];

[data writeToFile: path atomically:YES];
[data release]


please look at the above code.
so if I create two separate functions for reading and writing with the code above, will that be fine???

plz have a look at the following code:

NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDire ctory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"data.plist"];

NSFileManager *fileManager = [NSFileManager defaultManager];

if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:@”data” ofType:@”plist”];

[fileManager copyItemAtPath:bundle toPath: path error:&error];
}

do i have to write the above code in applicationDidFinishLaunching or somewhere else.

I'm confused where to put all these because i want to retrieve all the data in the plist at the time of level selection coz i have assigned stars to the user according to their score and it is displayed with the levels in the level sel screen. and the scores are written at the time of gameplay in the gamescene
xcoder.ios is offline   Reply With Quote
Old 04-26-2012, 10:59 PM   #18 (permalink)
Registered Member
 
Join Date: Jul 2009
Location: North America
Posts: 53
shimmy is on a distinguished road
Default

Quote:
Originally Posted by xcoder.ios View Post
sorry for the vague question.

for Reading :

NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile: path];

//load from savedStock example int value
int value;
value = [[savedStock objectForKey:@"value"] intValue];

[savedStock release];

for Writing :

NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithContentsOfFile: path];

//here add elements to data file and write data to file
int value = 5;

[data setObject:[NSNumber numberWithInt:value] forKey:@”value”];

[data writeToFile: path atomically:YES];
[data release]


please look at the above code.
so if I create two separate functions for reading and writing with the code above, will that be fine???

plz have a look at the following code:

NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDire ctory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"data.plist"];

NSFileManager *fileManager = [NSFileManager defaultManager];

if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:@”data” ofType:@”plist”];

[fileManager copyItemAtPath:bundle toPath: path error:&error];
}

do i have to write the above code in applicationDidFinishLaunching or somewhere else.

I'm confused where to put all these because i want to retrieve all the data in the plist at the time of level selection coz i have assigned stars to the user according to their score and it is displayed with the levels in the level sel screen. and the scores are written at the time of gameplay in the gamescene

As I said, if you have a class that manages the loading and saving of the data, you can just store the data in a member variable for that class. Depending on the context, you don't necessarily need to write to file every single time something changes. You could write to file when the view changes, or when the view returns etc. You could just save and manipulate the data within the member variable, and then save it to file at appropriate times.

If you have a class like that, you can initialize the class' dictionary in viewdidload or some init method. You could do it in applicaiton did finish launching, but since you probably go from there into a view controller, you might as well load it there.

Also, in the latest versions of XCode you have something called ARC (Automatic Retain Counting) that eliminates the need for calls to release etc.

Also, another very important point (this was a stumbling block for me too when I was starting out). You can't write to resource files (these are files which you create in*XCode that are part of the application bundle). They are read-only. What you want is to use the documents directory. This is how you get a path for a document: (presented in the form of some useful functions. I use these and other functions in a file that I import to other files in my project so that I can quickly retrieve file paths etc.)

NSString* getPathForDocument (NSString* name) {
NSString* documentsDirectory = getDocumentsDirectory();
return [documentsDirectory stringByAppendingPathComponent:name];
}

NSString* getDocumentsDirectory (){
return [NSSearchPathForDirectoriesInDomains(NSDocumentDire ctory, NSUserDomainMask, YES) objectAtIndex:0];
}


Input parameter for first function, "name", would be full file name, including extension type, e.g. AllScores.plist.

Last edited by shimmy; 04-26-2012 at 10:59 PM. Reason: ARC stands for Auto Retain Counting, not reference
shimmy is offline   Reply With Quote
Old 04-26-2012, 11:11 PM   #19 (permalink)
Registered Member
 
Join Date: Jul 2009
Location: North America
Posts: 53
shimmy is on a distinguished road
Default

Also, read the earlier posts more thoroughly. A lot of what you're asking has already been explained in this thread.
shimmy is offline   Reply With Quote
Reply

Bookmarks

Tags
modify, plist, resource, xcode

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 356
9 members and 347 guests
7twenty7, blueorb, fredidf, iAppDeveloper, iGamesDev, Mah6447, mottdog, sacha1996, Touchmint
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,667
Threads: 94,120
Posts: 402,898
Top Poster: BrianSlick (7,990)
Welcome to our newest member, host number one
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 03:34 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0