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 05-13-2009, 08:31 PM   #1 (permalink)
New Member
 
Join Date: May 2009
Posts: 7
kawititnow is on a distinguished road
Default Help!! Not writing to plist file properly

Hello all, first time poster so please be gentle.

The objective of my program is a navigation-based app, that reads objects from a plist file. Each row is selectable which opens up a detail view (type, date, description, etc). The user has the option to add "events" (via the AddViewController) which are to be written to the plist file and added to the table.

I'm able to read in the file and even write to the file, however when I write to the file it only inserts the last event and overwrites all previous data. Leaving me with only one entry. On top of that the format is somewhat different from the orginal plist format...

The error is obviously in my write code, but I'll also give you the plist format and read code to give better focus.

PLIST:
Code:
<plist version="1.0">
<dict>
   <key>Rows</key>
   <array>
      <dict>
         <key>type</key>
         <string>Type1</string>
         <key>description</key>
         <string>This is the description</string>
          etc...
      </dict>
      <dict>
         <key>type</key>
         <string>Type2</string>
         <key>description</key>
         <string>This another description</string>
         etc...
      </dict>
   </array>
</dict>
</plist>
This is my file read code from the applicationDidFinishLaunching method:
Code:
//Check to see if file exists
		
	//Resouce directory path
	NSString *resourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Data.plist"];

	//Documents directory path
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *DataPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Data.plist"];
		
	NSFileManager *fileManager = [NSFileManager defaultManager];
	
	//see if Data.plist exists in the Documents directory
	if (![fileManager fileExistsAtPath:DataPath]) {
		[fileManager copyItemAtPath:resourcePath toPath:DataPath error:nil];
	}
//END OF CHECK TO SEE IF FILE EXISTS
	
	//Load Data.plist from documents directory
	NSString *errorDesc = nil;
	NSPropertyListFormat format;
	NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:DataPath];
	NSDictionary *tempDict = (NSDictionary *)[NSPropertyListSerialization propertyListFromData:plistXML mutabilityOption:NSPropertyListMutableContainersAndLeaves format:&format errorDescription:&errorDesc];
	self.data = tempDict;
	[tempDict release];
self.data is a NSDictionary. Should it be a NSMutableDictionary?!?

Lastly the following is my save method from my AddViewController:
Code:
- (void)save:sender {
	//Gets type from UISegmentedControl
	NSInteger segIndex = [segType selectedSegmentIndex];
	type = [segType titleForSegmentAtIndex:segIndex];
	
	//Gets description from UITextView
	description = descriptionView.text;
		
	//Gets date from UIDatePicker
	date = [dateAndTime date];
	
	
	//Writes to plist file
	NSString *errorDesc;
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *documentsDirectory = [paths objectAtIndex:0]; 
	NSString *DataPath = [documentsDirectory stringByAppendingPathComponent:@"Data.plist"];
	NSDictionary *plistDict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects: type, date, description, nil] forKeys:[NSArray arrayWithObjects:@"type", @"date", @"description", nil]];
	NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorDesc];
	if (plistData) {
			[plistData writeToFile:DataPath atomically:YES];
	}
	
	[self.navigationController popViewControllerAnimated:YES];

	
}
Any help is greatly appreciated.
kawititnow is offline   Reply With Quote
Old 05-13-2009, 10:06 PM   #2 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 536
eddietr is on a distinguished road
Default

First of all, this is the perfect way to ask the question. Great first post. You stated clearly what you are trying to do. You stated clearly what is actually happening and how it differs from your expectations. And you used the code tags! (Bless you!)

You didn't ask someone to write the code for you. And you didn't shout at us that you need someone to do this for you ASAP! Seriously, this thread should be a sticky.

So anyway, the main issue here is that you are overwriting the plist file with the latest entry. Here is the offending line:

Code:
NSDictionary *plistDict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects: type, date, description, nil] forKeys:[NSArray arrayWithObjects:@"type", @"date", @"description", nil]]
Do you see what you're doing here? You are creating a new dictionary and then writing that dict out to the file. What you really want to do is add this new item to the existing dictionary (self.data) and then write the whole dictionary out to the file. Does that make sense?

Of course, to do that you do need to make sure self.data is mutable. You passed the correct option to make it mutable when you read it from the file, so that's good. You just need to declare it mutable now so the compiler knows that.

And, btw, you don't want to release tempDict there when you read the file, because it is already autoreleased. Hopefully you've declared your "data" property with "retain" attribute?

Hope that helps?
eddietr is offline   Reply With Quote
Old 05-14-2009, 08:52 AM   #3 (permalink)
New Member
 
Join Date: May 2009
Posts: 7
kawititnow is on a distinguished road
Default

Thanks for the input eddietr!!

What you are saying makes perfect sense. I was writing that one instance of the dictionary as opposed to adding it to the self.data and writing that.

I made some changes, but I'm still not quite there, but I am much closer.

First off I declared self.data as a NSMutableDictionary.
Then I added the following in the save method of AddViewController:
Code:
- (void)save:sender {
	//Gets type from UISegmentedControl
	NSInteger segIndex = [segType selectedSegmentIndex];
	type = [segType titleForSegmentAtIndex:segIndex];
	
	//Gets description from UITextView
	description = descriptionView.text;
		
	//Gets date from UIDatePicker
	date = [dateAndTime date];
		
	//Writes to plist file
	NSString *errorDesc;
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *documentsDirectory = [paths objectAtIndex:0]; 
	NSString *DataPath = [documentsDirectory stringByAppendingPathComponent:@"Data.plist"];

        //Creating a delegate so I can access the mutable dictionary data
        DataAppDelegate *delegate = (DataAppDelegate *)[[UIApplication sharedApplication] delegate];

	NSDictionary *plistDict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects: type, date, description, nil] forKeys:[NSArray arrayWithObjects:@"type", @"date", @"description", nil]];
	NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorDesc];

        //Adding plistDict to data Dictionary
        [delegate.data addEntriesFromDictionary:plistDict];

	if (plistData) {
		[delegate.data writeToFile:DataPath atomically:YES];
	}
	
	[self.navigationController popViewControllerAnimated:YES];

	
}
This didn't delete the previous entries (YAY!!!) but it just added it after the array, instead of inside the array.

Should I maybe use:
Code:
[delegate.data setObject:plistDict forKey:@"Rows"];
I'm away from my home computer at the moment and doing all of this from memory, otherwise I would just try it and see if it works...
kawititnow is offline   Reply With Quote
Old 05-14-2009, 12:16 PM   #4 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 536
eddietr is on a distinguished road
Default

So just go back and understand your structure again.

You have a dictionary (call this the root dictionary, you've called it 'data') with one key and one value. The key is "rows" and the value is an array.

That array, in turn, is an array of dictionaries.

And now you have a new dictionary you want to add within that array. So you don't want to add that new dictionary to 'data'. You want to add it to the array that is stored inside data.

If you do this:

Code:
[delegate.data setObject:plistDict forKey:@"Rows"];
then you are going to replace the entire array with your new dictionary. That's not what you want.
eddietr is offline   Reply With Quote
Old 05-14-2009, 09:11 PM   #5 (permalink)
New Member
 
Join Date: May 2009
Posts: 7
kawititnow is on a distinguished road
Default

Yeah after I thought about it some I realized that might be the case.

After some playing around, I finally got it to work like I needed it too.

First I added a NSMutableArray to DataAppDelegate from the data dictionary
Code:
dataArray = [data objectForKey@"Rows"];
This allowed me to access the array itself back in the save method...

Then in the save method I added the plistDict to the array:
Code:
[delegate.dataArray addObject:plistDict];
Then replaced the array for the key "Rows":
Code:
[delegate.data setObject:delegate.dataArray ForKey:@"Rows"];
And finally wrote the updated data to the file!!!

Thanks so much to eddietr for all the help. Thank you for not giving me the code, but rather pushing me in the right direction and realizing what I was doing wrong and what I needed to do.
kawititnow is offline   Reply With Quote
Old 05-14-2009, 09:52 PM   #6 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 536
eddietr is on a distinguished road
Default

Great, I'm glad it worked out.

Just one more point. This line here:

Code:
[delegate.data setObject:delegate.dataArray ForKey:@"Rows"];
is actually unnecessary. Because 'dataArray' is not a copy of the array inside 'data', it is a pointer to the array.

So you're working with the same array. So after you add an object to that array, there is no reason to set that array back into the dictionary. All you are doing is replacing the array with the exact same array.
eddietr is offline   Reply With Quote
Old 07-11-2010, 10:00 AM   #7 (permalink)
iPhoneDev
 
Join Date: Dec 2009
Posts: 33
sivasankarp is on a distinguished road
Send a message via Yahoo to sivasankarp
Default Hi

Hi

Me too facing the same problem can any one share their code of adding the datas to the plist
i hav my PLIST as follows:
<?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>
<string>http://localhost:8888/sampleTest</string>
</array>
</plist>
sivasankarp is offline   Reply With Quote
Reply

Bookmarks

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: 338
7 members and 331 guests
givensur, guusleijsten, ipodphone, jbro, mer10, n00b, yomo710
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,649
Threads: 94,113
Posts: 402,881
Top Poster: BrianSlick (7,990)
Welcome to our newest member, Anwerbl
Powered by vBadvanced CMPS v3.1.0

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