Wednesday, March 9, 2011

Read and write data from Plist file



Note : Plists are used to store static data only once you update the values in the plist then your old values will be lost. Hence plist should be used only to hold static values, but if you want to hold the old values then in that case you need to keep a copy of all the values in the plist in a collection type like mutable array of mutable dictionary and update all of them when you are performing any operations in the plist.

Note 2 : The files stored in the project bundle have read only access and if you want to perform read, write, delete operation then in that case the file needs to be copied to your application document directory.


It has been quite a time since we are doing iPhone Programming, and in my earlier blog post i have shown you a way to store user data, now if you want to store some small amount of data lets say strings or some image URLs then in that case you wont be using core data or SQLITE neither you would be using a Mutable array because once you restart your app all the data stored in that array would be lost.

So the solution for this is the property list file or plist file, their is one property list file that will be present in each and every iPhone project that you have created the location to that file is in the resource folder, this property list file handles your application oriented settings now of course you may have your own property list file and for that all you have to do is


a) Select the resource folder and right click on it and select add new file, once done the images below will guide you for the next steps






You can add new items in the property list by clicking the button that is at the end of the table, internally in a property list every data is maintained in an XML format.


Design Phase: For this sample app i will add some data in the property list file which would be present in the bundle and then try to read it and then in phase 2 i am going to programatically add data in the property list file save it in the documents folder of the document directory and then try to read the newly added data.


Phase 1: Adding data to the property list present in the bundle and try reading it.

Step 1: Select the property list file and click on the button that is present at the end of the table, when you click it a new item would appear you can set the type of this new item (String, array, dictionary etc).



Property list saves every data in a key value pair, so its better if we give a proper name in the key section of the property list, (For this demo i have kept the type as array and the name of my key is handset and i have added different types of handset to my property list here's a view)



Step 2: Now we are done setting the values inside our property list file, i will not be taking any viewController files here, i will write a function called as readData which will help me in reading the data of the plist file from the bundle. Here's a view at the code of the readData method which is written in the appDelegate.m file of my project

-(void)readData
{
//stores the path of the plist file present in the bundle
NSString *bundlePathofPlist = [[NSBundle mainBundle]pathForResource:@"Mobiles" ofType:@"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:bundlePathofPlist];
NSArray *dataFromPlist = [dict valueForKey:@"HandSet"];
for(int i =0;i<[dataFromPlist count];i++)
{
NSLog(@"Mobile handset no %d is %@",i+1,[dataFromPlist objectAtIndex:i]);
}
}



Code Explanation: Since i have stored an array in my plist file i am using NSArray class to read the data from the plist by supplying the proper key value using NSDictionary class, i have used NSDictionary because as i said earlier every data in the plist is stored in the key value pair. Here's the output of the above code



Phase 2: Storing the Plist file from the bundle to the document directory and adding data to it

Step 1: The first step would be to copy the plist file from the bundle to the document directory folder, and then adding data to the plist file that is newly created in the documents folder of the document directory, here's the code to do that

-(void)CreateFileandAddData
{
NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolder = [documentPath objectAtIndex:0];

//the below variable is an instance of the NSString class and is declared inteh .h file
newPlistFile = [documentFolder stringByAppendingPathComponent:@"NewPlist.plist"];
NSString *bundleFile = [[NSBundle mainBundle]pathForResource:@"Mobiles" ofType:@"plist"];

//copy the file from the bundle to the doc directory
[[NSFileManager defaultManager]copyItemAtPath:bundleFile toPath:newPlistFile error:nil];
NSMutableDictionary *addData = [NSMutableDictionary dictionaryWithContentsOfFile:newPlistFile];
NSArray *newHadsets = [[NSArray alloc]initWithObjects:@"LG",@"Samsung",@"Android",@"Spice",nil];
//adding the new objects to the plist
[addData setObject:newHadsets forKey:@"HandSet"];
//finally saving the changes made to the file
[addData writeToFile:newPlistFile atomically:YES];
}

Step 2: Now if you want to read the data present in the plist file then in that case you can alter a small piece of line that was present in our earlier function called as readData, here's a view to that as well

-(void)readData
{
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:newPlistFile];
NSArray *dataFromPlist = [dict valueForKey:@"HandSet"];
for(int i =0;i<[dataFromPlist count];i++)
{
NSLog(@"Mobile handset no %d is %@",i+1,[dataFromPlist objectAtIndex:i]);
}
}

Step 3: Now when you call both the functions you will get the below output into your console


Note: A better option if you are working with document path  it's better to create a function with the return type as string containing the document directory path and then use that function.


-(NSString*) DocumentDirectoryPath
{
NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolder = [documentPath objectAtIndex:0];
return documentFolder;
}


You may download the source code of this demo from here. The demo contains a helper file for plist you may modify it as per your needs, in case if you find any issues or errors then in that case you may mail me or mention your query as a comment.

I hope that this post helped you out, our comments and suggesstions are always welcome, until then Happy iCoding and have a great Day.

15 comments:

  1. Really great article...thanks!

    ReplyDelete
  2. Thank you very much ! Nice article ...

    ... mayby you want to add something like:
    if (![[NSFileManager defaultManager] fileExistsAtPath:newPlistFile]) {
    [[NSFileManager defaultManager]copyItemAtPath:bundleFile toPath:newPlistFile error:nil];
    }

    ReplyDelete
  3. please sir, do u like to send me the code
    i want load a plist from url and want to show the contents in my app.

    my email is:

    mahendrachouhan1@gmail.com

    ReplyDelete
  4. instead of changing the mobile names...can i add it to the original plist?..the list starting from LG should start after Motorola?

    ReplyDelete
  5. Chandu: Yes you may do that if that is something that your business logic requires

    ReplyDelete
    Replies
    1. can u please tell me how to do so.

      Delete
    2. luking sexi @radix

      Delete
  6. great explanation....

    ReplyDelete
  7. Can You help me in passing one plist value into other plist..i need to update the scores and hint count dynamically..so after playing level 1 that score n hint should be added in next classes of plists..so plz help me..

    ThankQ in Advance

    ReplyDelete
  8. nice article...thanks!

    it's really helpful for me :)

    ReplyDelete
  9. hi, can you give me the code as zip as I am new to this field i am finding this very hard

    ReplyDelete
  10. @Deepak : I have updated the post and have added the demo code as requested by you. Do let me know if this helps you.

    ReplyDelete
  11. It has been quite a time since we are doing iPhone Programming, and in my earlier blog post i have shown you a way to store user data

    ReplyDelete
  12. This is an interesting blog, write very well, thank you for your sharing. more information here

    ReplyDelete
  13. Check this library: https://github.com/fabiocaccamo/FCFileManager

    ReplyDelete