Ios 将自定义对象附加到txt文件并将其读回

Ios 将自定义对象附加到txt文件并将其读回,ios,xcode,ios-app-group,Ios,Xcode,Ios App Group,我正在为iOS开发待办事项列表应用程序。我有一个名为ToDoItem的自定义类。我的设计是将用户的内容写入文本文件,并在用户再次打开应用程序时从文件中读取。我已经为ToDoItem类实现了符合NSCoding协议的方法 下面给出了写入数据的方法 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // if cancel button is pressed if (sender!=self.saveBtn

我正在为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];
    } 
}}
下面给出了读取数据的方法

- (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::]:Uncrunessible archive”异常。 我关心的是,我只想在用户保存数据时附加ToDoItem对象,并在用户重新启动应用程序时再次检索所有信息

非编码方法

- (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;
}

提前感谢

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

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


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

假设:

\u appFile
:包含plist文件路径的NSString变量

\uuuu toDoItems
:一个初始化的NSMutableArray变量,用于保存todo项

这两种方法都使用
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
     }
}

请为您的
ToDoItem
类显示您的
NSCoding
方法。顺便说一下,在第二个代码段中,一旦它起作用,
arr
将是一个
ToDoItems
数组,因此您不需要迭代并将对象添加到数组中-您只需将
arr
分配给
self即可。ToDoItems
@w11我添加了NSCoding方法。我还尝试直接设置数组[\u toDoItems arrayByAddingObjectsFromArray:arr]。但仍然面临同样的问题error@Paulw11如果文件包含多个项,则第二个代码段将引发异常。这正是我遇到麻烦的地方。对不起,我只是更仔细地研究了你的保存方法——你不能附加到文件中。你每次都需要替换文件。@Paulw11你是说每次我都要覆盖整个内容吗?。即使我这样做了,当我为阅读而取消归档数据时,即当有多个项目时,我也会面临问题。你能帮我吗谢谢你的关心。我将尝试实施您的建议并让您知道我尝试了您的方法,但是在prepareForSegue方法中添加数据时出现异常。异常发生在哪里?[itemDataArray addObject:[NSKeyedArchivedDataWithRootObject:item]];}。我认为在写入文件时不能归档多个根对象。我在几个项目中使用了这种语法。设置一个断点,并查看变量ID,了解您的方法。让它工作起来。谢谢