Eduardo Ferreira
Eduardo Ferreira

Reputation: 11

How to write data in .plist?

I'm trying to save some comments in a plist, that's OK cause its just a prototype. The problem is that i can read from plist but when I try to write and read after that, it throws an "array out of bounds" exception. I can't figure it out what I'm doing wrong here.

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Comments" ofType:@"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];


NSMutableDictionary *newComment = [NSMutableDictionary dictionary];
[newComment setValue:commentTitle.text forKey:@"title"];
[newComment setValue:comment forKey:@"comment"];


[plistArray addObject:newComment];
[plistArray writeToFile:filePath atomically:NO];

That works fine, then i try to read:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Comments" ofType:@"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];


NSMutableDictionary *dictionary = (NSMutableDictionary *) [plistArray objectAtIndex:0];

NSLog(@"%@", [dictionary objectForKey:@"title"]);

And it throws the exception.

If I add the item manually to the plist, it works fine, i guess it means that my reading code its fine.

Could it be the structure of my plist?

<?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>
 </array>
 </plist>

* Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (1) beyond bounds (1)'

I added the "description" to the array before writing to the plist. If i use the following code:

NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
//    NSString *aFilePath = [NSString stringWithFormat:@"%@/Comments.plist", aDocumentsDirectory];
//
//    NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:aFilePath];

The return is (null)

But if i use:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Comments" ofType:@"plist"];
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filePath];

i can see the contents of the array, and its all working properly.

The problem is: In both ways i cant write to the file, it keeps returning "NO". And i already checked the permissions

Upvotes: 1

Views: 4584

Answers (4)

Roshit
Roshit

Reputation: 1579

You are trying to write the file into mainBundle. Definitely not possible. You will have to write the plist file to Documents or Application Support folder of the app.

Create File Path in Documents Directory :

NSString *aDocumentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

NSString *aFilePath = [NSString stringWithFormat:@"%@/Comments.plist", aDocumentsDirectory];

Write to FilePath

[plistArray writeToFile:aFilePath atomically:YES];

Read From FilePath

NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:aFilePath];

Upvotes: 4

TheAmateurProgrammer
TheAmateurProgrammer

Reputation: 9392

First of all, why are you writing a file into your bundle?

Then, to address your problem, check if you actually did write the file.

if ([plistArray writeToFile:filePath atomically:NO])
    NSLog (@"Written");
else
    NSLog (@"Not Written");

Also, log your array when you're read it using -(void)description to check the contents of the dictionary.

Edit

As you said that you're not writing to your plist. For now, just create a test plist on your desktop.

NSString *testPath = [[NSString stringWithString:@"~/Desktop/Comments.plist"] stringByExpandingTildeInPath];
if ([plistArray writeToFile:testPath atomically:NO])
    NSLog (@"Written");
else
    NSLog (@"Not Written");    

If that still returns Not Written, then there's something wrong with your dictionary. Which I doubt because it's just strings (Though they could be placeholders for asking your question on stackoverflow. The docs states that the classes in the dictionary must be of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary). If that says written though, I'm guessing it doesn't write to your bundle because of permissions, which then you have to change your plist location to somewhere else other than your bundle, which I highly recommend.

Upvotes: 0

Krumelur
Krumelur

Reputation: 32497

I see two problems with your code:

  1. (May or may not be a problem). If the file does not exist initially, the initWithContentsOfFile: selector will return nil, causing the rest of your code to be no-ops.

  2. (Probably the cause). You may not write to the bundle resources directory. Store your file in the Documents or Caches directory instead.

To locate your documents directory, use something like this:

- (NSString*) pathForDocument:(NSString*)documentName {
    NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    if(documentDirectories.count < 1) return nil;
    return [[documentDirectories objectAtIndex:0] stringByAppendingPathComponent:documentName];
}

Upvotes: 0

gregorkas
gregorkas

Reputation: 137

If you only put one item in the array, you should obviously use index 0 instead of 1 when reading from it:

NSMutableDictionary *dictionary = (NSMutableDictionary *) [plistArray objectAtIndex:0];

Upvotes: -2

Related Questions