1

データを保存する方法に関するいくつかの情報: ユーザーが追加および削除するビュー コントローラーの配列があります (これは基本的にメモを取るアプリであり、ビュー コントローラーはフォルダーです)。View Controller には、アプリが保存する必要があるいくつかの動的プロパティと、その中のメモ配列があり、Note オブジェクト自体にも、保存する必要があるいくつかのプロパティがあります。もちろん、View Controller と Notes の両方に適切な NSCoding 機能があります。これは、たとえば View Controller のものです。

- (void) encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:self.folderName forKey:@"lvcTitle"];
    [encoder encodeObject:[NSNumber numberWithInt:self.myPosition] forKey:@"myPosition"];
    [encoder encodeObject:self.notes forKey:@"notes"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    self.folderName = [decoder decodeObjectForKey:@"lvcTitle"];
    NSNumber *gottenPosition = [decoder decodeObjectForKey:@"myPosition"];
    int gottenPositionInt = [gottenPosition intValue];
    self.myPosition = gottenPositionInt;
    self.notes = [decoder decodeObjectForKey:@"notes"];
    return self; }

Controller の配列は Singleton クラスに属します。NSCoding は単純なものと考えられていても、かなり混乱しますが、これまでのところ、Singleton に Controllers 配列を保存するように指示するだけで成功しました。これにより、View Controller に含まれるすべてのプロパティが (正常に) 保存されますそれらのプロパティとすべてのメモのプロパティも同様です。シングルトンのコードは次のとおりです。

- (void) saveDataToDisk:(id)object key:(NSString *)key {
    NSString *path = [self pathForDataFile];

    NSMutableDictionary *rootObject;
    rootObject = [NSMutableDictionary dictionary];

    [rootObject setValue:object forKey:key];
    [NSKeyedArchiver archiveRootObject:rootObject toFile:path]; } 

- (void) loadDataFromDisk {
    NSString *path = [self pathForDataFile];
    NSDictionary *rootObject;

    rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:path];    

    if ([rootObject valueForKey:@"controllers"] != nil) {
        self.controllers = [NSMutableArray arrayWithArray:[rootObject valueForKey:@"controllers"]];
        firstRun = false;

        LabeledViewController *lastOneThere = [self.controllers objectAtIndex:self.controllers.count-1];
        lastOneThere.isFolderAddView = TRUE;

    }else{
        firstRun = true;
    } 
}

次に、Folder View Controller で save メソッドを数回呼び出します。

[singleton saveDataToDisk];

そして、アプリのロード時にランダムにクラッシュするまで、これは数回うまく機能します。原因は、heightForRowAtIndexPath です。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

Note *currentNote = [self.notes objectAtIndex:indexPath.row];
if (currentNote.associatedCellIsSelected) {
    return currentNote.myHeight + NOTE_BUTTON_VIEW_HEIGHT;
}

return NORMAL_CELL_FINISHING_HEIGHT;  }

次のエラーが表示されます。

2012-06-07 08:28:33.694 ViewTry[1415:207] -[__NSCFString associatedCellIsSelected]: unrecognized selector sent to instance 0x8904710
2012-06-07 08:28:33.696 ViewTry[1415:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString associatedCellIsSelected]: unrecognized selector sent to instance 0x8904710'
*** First throw call stack:

「__NSCFString」と「インスタンスに送信された認識されないセレクター」は、関連するCellIsSelectedがブール値であるため、あるべきではない場所に文字列があることを意味することを理解しています。ただし、heightForRow で「currentNote.myHeight」のみを返すと、float である myHeight でも同じ __NSCF エラーが発生します。heightForRow をまとめて取り出すと、適切な高さの定義を除いてすべてが機能します。

ところで、heightForRowAtIndexPath が参照しているテーブル ビューは、notes 配列が作成されて入力された後に loadView で作成されます。なぜこのエラーがたまにしか表示されないのか (アプリを 5 ~ 10 回開く、保存する、閉じる、再度開くなど)、一見ランダムに見える理由がわかりません。この動作の原因となるパターンが見つかりません。ポインタはありますか?

混乱して申し訳ありません。私は iOS プログラミングが初めてで、ここで多くのことを間違っていると確信しています。

編集 - また、アプリがクラッシュすると、アンインストールして再インストールするまで (heightForRow を無効にしない限り) 再度開くたびにクラッシュしたままになります。

4

1 に答える 1

1

「認識されないセレクター」エラーが表示され、レシーバー タイプがコーディングしたオブジェクトの種類ではない場合 (この場合__NSCFStringは ではなくNote)、使用しようとしていたオブジェクトが時期尚早に解放され、そのアドレス空間は、新しいオブジェクトを割り当てるために再利用されています。

修正は、余分なリリースが発生している場所 (または保持が発生していない場所) を追跡することに依存します。@property 宣言を表示できればnotes、状況がさらに明らかになる可能性があります。

簡単にできることの 1 つは、メニューから [Product] -> [Analyze] を選択し、フラグが付けられたものをすべて修正することです。すべてをキャッチするわけではありませんが、開始するのに適した健全性チェックです。

于 2012-06-05T19:48:27.910 に答える