1

iOS用のtodoリストアプリを開発しています。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 を 1 つだけファイルに書き込んで読み取ることができるようになりました。ToDoItem の複数のオブジェクトを書き込んで読み返すと、"[NSKeyedUnarchiver initForReadingWithData:]: incomprehensible archive " という例外が発生します。私の懸念は、ユーザーがデータを保存したときに ToDoItem オブジェクトを追加し、ユーザーがアプリを再起動したときにすべての情報を再度取得したいということです。

NSCoding メソッド

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

テキスト ファイルではなく、プロパティ リスト ファイルを使用することをお勧めします。todoItems を plist ファイルに読み込んで保存するソリューションです。

仮定:

_appFile: plist ファイルへのパスを含む NSString 変数

__toDoItems: todo アイテムを保持するための初期化された 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 に答える
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 に答える