1

我正在为 iOS 开发待办事项列表应用程序。我有一个名为 ToDoItem 的自定义类。我的设计是将用户内容写入文本文件,并在用户再次打开应用程序时从文件中读取。我已经为我的 ToDoItem 类实现了确认 NSCoding 协议的方法。

下面给出写入数据的方法

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// if cancel button is pressed
if (sender!=self.saveBtn) {
    return;
}
// if save button is pressed
else{
    if (self.addField.text.length>0) {
        ToDoItem *item = [[ToDoItem alloc] init];
        item.itemName = self.addField.text;
        item.isDone = FALSE;
        item.row = [ToDoListTableTableViewController getCount];
        self.toDoItem = item;


        NSMutableArray *arr = [NSMutableArray arrayWithContentsOfFile:_appFile];
        [arr addObject:item];

        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];

        NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:_appFile];

        [handle seekToEndOfFile];
        [handle writeData:data];
        [handle closeFile];

    }
}

下面给出读取数据的方法

- (void)loadData{
if ([[NSFileManager defaultManager] fileExistsAtPath:_appFile]) {

    NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:_appFile];

    if (handle) {
        NSData *data = [handle readDataToEndOfFile];
        if (data) {
            ToDoItem *item;
            NSMutableArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];

            for (item in arr) {
                [_toDoItems addObject:item];
            }
        }
        [handle closeFile];
    } 
}}

现在我只能将单个 ToDoItem 写入文件并能够读取它。如果我写了多个 ToDoItem 对象,在读回它时,我会得到“[NSKeyedUnarchiver initForReadingWithData:]: incomprehensible archive”异常。我担心的是我只想在用户保存数据时附加我的 ToDoItem 对象,并在用户重新启动应用程序时再次检索所有信息。

NS编码方法

- (void)encodeWithCoder:(NSCoder *)aCoder{
[aCoder encodeObject:_itemName forKey:ITEMNAME];
[aCoder encodeObject:_date forKey:DATE];
[aCoder encodeBool:_isDone forKey:DONE];
[aCoder encodeInteger:_row forKey:ROW];
}

- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
if (self) {
    _itemName = [aDecoder decodeObjectForKey:ITEMNAME];
    _date = [aDecoder decodeObjectForKey:DATE];
    _isDone = [aDecoder decodeBoolForKey:DONE];
    _row = [aDecoder decodeIntegerForKey:ROW];
}
return self;
}

提前致谢

4

2 回答 2

1

添加新项目时,不能将新数据附加到文件末尾 - 每次都需要完全替换文件。

您需要将新项目添加到现有的项目数组中,然后保存完整数组的存档。如果您的新 todo 项目视图控制器只是返回新项目或 nil 并在“外部”VC 中完成保存,它可能会更干净

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

// if cancel button is pressed
if (sender!=self.saveBtn) {
    return;
}
// if save button is pressed
else{
    if (self.addField.text.length>0) {
        ToDoItem *item = [[ToDoItem alloc] init];
        item.itemName = self.addField.text;
        item.isDone = FALSE;
        item.row = [ToDoListTableTableViewController getCount];
        self.toDoItem = item;

        [self.toDoItems addObject:item];  // This needs to be a reference to the array that holds all of your todo items

        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.toDoItems];

        NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:_appFile];

        [handle truncateFileAtOffset:0];
        [handle writeData:data];
        [handle closeFile];

    }
}
于 2015-06-29T07:23:59.717 回答
1

我建议使用属性列表文件而不是文本文件。这是在 plist 文件中加载和保存 todoItems 的解决方案。

假设:

_appFile: 一个 NSString 变量,包含 plist 文件的路径

__toDoItems: 一个初始化的 NSMutableArray 变量来保存待办事项

两种方法都使用NSPropertyListSerialization它提供了更多的读写选项

- (void)loadData
{
    NSDictionary *prefs = nil;
    NSData *plistData = [NSData dataWithContentsOfFile:_appFile];
    if (plistData) {
        prefs = (NSDictionary *)[NSPropertyListSerialization
                                        propertyListWithData:plistData
                                        options:NSPropertyListImmutable
                                        format:NULL
                                        error:nil];
    }
    if (prefs) {
        NSArray *itemDataArray = prefs[@"todoItems"];
        if (itemDataArray) {
            [_toDoItems removeAllObjects]; // might be not needed
            for (itemData in itemDataArray) {
                 [_toDoItems addObject:(ToDoItem *)[NSKeyedUnarchiver unarchiveObjectWithData:itemData]];
            }
        }
    }
}


- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    // if cancel button is pressed
    if (sender != self.saveBtn) {
        return;
    }
    // if save button is pressed
    else {
        NSMutableArray *itemDataArray = [[NSMutableArray alloc] init];
        for (ToDoItem *item in _toDoItems) {
            [itemDataArray addObject:[NSKeyedArchiver archivedDataWithRootObject:item]];
        }
        NSError *error = nil;
        NSDictionary *prefs = @{@"todoItems" : itemDataArray};
        NSData *plistData = [NSPropertyListSerialization dataWithPropertyList: prefs
                                                         format:NSPropertyListBinaryFormat_v1_0
                                                        options:0 
                                                          error:&error];

        if (plistData) {
         [plistData writeToFile:_appFile atomically:YES];
     }
        else {
        // do error handling
     }
}
于 2015-06-29T07:40:01.067 回答