NSDictionary value replacing instead of adding in

2020-02-13 04:21发布

问题:

hi i tried to add values(book id,page number,notes) from NSdictionary to Plist but each time the new value replacing the previous one?but i need all values in plist my code for adding dictionary to plist is

NSString *bid=@"95";
NSString *pnum=@"12";
userNotes=[[NSMutableDictionary alloc]init];
[userNotes setValue:userNotesTextview.text forKey:@"notes"];
[userNotes setValue:bid forKey:@"bookid"];
[userNotes setValue:pnum forKey:@"pagenumber"];
userNotesView.hidden=YES;
_background.hidden = YES;
userNotesTextview.text=@"";
[self savingMetaData];
  NSMutableArray *notes=[[NSMutableArray alloc]init];
  [notes addObject:userNotes];

  NSMutableDictionary *final=[[NSMutableDictionary alloc]init];
  [final setValue:notes forKey:@"usernotes"];
  [final writeToFile:metaDataPath atomically:YES];

and my plist look like

how can i solve this problem

回答1:

Fetch the existing array from the plist as below, but first make sure you have copied you plist to Documents directory or, to some writable folder as below

NSFileManager *fileManager=[NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *docPath=[[paths objectAtIndex:0] stringByAppendingString:@"yourplist.plist"];
BOOL fileExists = [fileManager fileExistsAtPath: docPath];
NSError *error = nil;
if(!fileExists) 
{
    NSString *strSourcePath = [[NSBundle mainBundle] pathForResource:@"yourplist" ofType:@"plist"];

    [fileManager copyItemAtPath:strSourcePath toPath:docPath error:&error];         

}

NSString *path = docPath;
NSMutableDictionary *plistdictionary = [[NSMutableDictionary alloc]initWithContentsOfFile:path];
NSMutableArray *notes=[plistdictionary objectForKey:@"usernotes"];
if(notes==nil){ 
   notes=[[NSMutableArray alloc] init]; 
}
NSString *bid=@"95";
NSString *pnum=@"12";
userNotes=[[NSMutableDictionary alloc]init];
[userNotes setValue:userNotesTextview.text forKey:@"notes"];
[userNotes setValue:bid forKey:@"bookid"];
[userNotes setValue:pnum forKey:@"pagenumber"];
[notes addObject:userNotes];

then finally

NSMutableDictionary *final=[[NSMutableDictionary alloc]init];
[final setValue:notes forKey:@"usernotes"];
[final writeToFile:docPath atomically:YES];

Note: You cannot write anything in MainBundle, so better to copy your plist to Documents directory and use from there..



回答2:

because plist can store value with unique key only. if you try to save value with same key it will replace old one with new value. so always save new value with new key (eg. item0, item1, item3 etc.)

following line will store two usernote with key @"usernotes1" and @"usernotes2" respectively

[final setValue:notes forKey:@"usernotes1"];
[final setValue:notes forKey:@"usernotes2"];


回答3:

Plist structure looks like this

You can create a UserNote model class.

#define kBookID @"bookid"
#define kPageNumber @"pageNumber"
#define kNotes @"notes"

@interface UserNote : NSObject

@property (nonatomic, copy) NSString *bookID;
@property (nonatomic, copy) NSString *pageNumber;
@property (nonatomic, copy) NSString *notes;

- (id)initWithDictionary:(NSDictionary *)dictionary;

+ (NSArray *)savedUserNotes;
- (void)save;

@end

Initialize

- (id)initWithDictionary:(NSDictionary *)dictionary
{
    self = [super init];
    if (self)
    {
        self.bookID = dictionary[kBookID];
        self.pageNumber = dictionary[kPageNumber];
        self.notes = dictionary[kNotes];
    }

    return self;
}

Find the document path of plist file in documents directory. If the plist file is not there create a new one and return the path.

+ (NSString *)userNotesDocumentPath
{
    NSString *documentsPath  = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"UserNotes.plist"];

    NSFileManager *fileManger = [NSFileManager defaultManager];
    if (![fileManger fileExistsAtPath:documentsPath])
    {
        NSString *bundleResourcePath = [[NSBundle mainBundle]pathForResource:@"UserNotes" ofType:@"plist"];
        NSArray *userNotes = [NSArray arrayWithContentsOfFile:bundleResourcePath];
        [userNotes writeToFile:documentsPath atomically:YES];
    }

    return documentsPath;

}

Fetches all saved usernotes from plist file.

+ (NSArray *)savedUserNotes
{
    NSString *documentsPath = [self userNotesDocumentPath];
    NSArray *savedNotes = [NSArray arrayWithContentsOfFile:documentsPath];
    NSMutableArray *savedUserNotes = [@[] mutableCopy];
    for (NSDictionary *dict in savedNotes) {
        UserNote *note = [[UserNote alloc]initWithDictionary:dict];
        [savedUserNotes addObject:note];
    }

    return savedUserNotes;

}

Saves a usenote to plist

- (NSDictionary *)userNoteDictionary
{
    return @{kBookID:self.bookID,kPageNumber:self.pageNumber,kNotes:self.notes};
}

- (void)saveUserNotesToPlist:(NSArray *)userNotes
{
    NSMutableArray *mutableUserNotes = [@[] mutableCopy];
    for (UserNote *note in userNotes) {
        NSDictionary *dict = [note userNoteDictionary];
        [mutableUserNotes addObject:dict];
    }
    NSString *documentsPath  = [UserNote userNotesDocumentPath];
    [mutableUserNotes writeToFile:documentsPath atomically:YES];
}

#pragma mark - Save

- (void)save
{
    NSMutableArray *savedNotes = [[UserNote savedUserNotes] mutableCopy];
    [savedNotes addObject:self];
    [self saveUserNotesToPlist:savedNotes];
}

In you viewController where user makes a note

- (IBAction)saveUserNoteButtonPressed:(UIButton *)button
{
    UserNote *note = [UserNote new];

    note.bookID = @"95";
    note.pageNumber = @"12";
    note.notes = self.userNotesTextview.text;

    [note save];
}

Demo Source Code