加载时,heightForRowAtIndexPath偶尔会崩溃,NSCoding - iOS

时间:2012-06-05 19:40:49

标签: ios cocoa nscoding heightforrowatindexpath

有关我保存数据的方式的一些信息:我有一组由用户添加和删除的视图控制器(这基本上是一个记笔记应用程序,视图控制器是文件夹)。视图控制器具有应用程序需要保存的几个动态属性以及其中的notes数组,然后Note对象本身具有一些需要保存的属性。 View Controllers和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; }

控制器数组属于Singleton类。尽管NSCoding被认为是简单的东西,但是我觉得很成功,只是告诉Singleton保存Controllers数组 - 然后(成功地)保存了视图控制器的所有包含属性,它们的属性和所有Notes的属性。以下是Singleton中的代码:

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

然后我在文件夹视图控制器中多次调用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”和“无法识别的选择器发送到实例”意味着在某个地方不应该有一个字符串,因为associatedCellIsSelected是一个bool。但是,如果我只在heightForRow中返回“currentNote.myHeight”,我也会得到与myHeight相同的__NSCF错误,这是一个浮点数。如果我一起取出heightForRow,除了适当的高度定义外,一切都有效。

顺便说一句,heightForRowAtIndexPath引用的表视图是在loadView后制作并填充了notes数组。我只是不明白为什么这个错误只会偶尔弹出一次(比如5-10打开,节省,关闭和重新打开应用程序),看似随机 - 我找不到导致这种行为的模式。有什么指针吗?

抱歉这个烂摊子,我是iOS编程的新手,我确信我在这里做了很多错事。

编辑 - 此外,一旦应用程序崩溃,每次重新打开它时都会崩溃(除非我禁用heightForRow),直到我卸载并重新安装它。

1 个答案:

答案 0 :(得分:1)

当您看到“无法识别的选择器”错误且接收器类型不是您编码的对象类型时(在这种情况下为__NSCFString而不是Note),可能性是您有一个您要使用的对象过早释放并且其地址空间被重用以分配新对象的问题。

修复程序取决于追踪额外释放发生的位置(或保留未发生)。如果您可以显示notes的@property声明,则可能会更清楚地了解情况。

快速做的就是从菜单中选择Product-> Analyze并修复它标记的任何内容。它不会捕捉到所有东西,但它是一个很好的理智检查开始。