在初始出现后更新NSOutlineView中的单元格

时间:2013-07-23 01:41:28

标签: macos cocoa nsoutlineview

我的应用

我的应用程序的目的是下载WWDC视频的字幕文件。字幕在名为“fileSequence0.webvtt”,“fileSequence1.webvtt”等的WebVTT文件中可用,位于视频和幻灯片文件所在目录的宏子目录中。

如果您有任何WWDC视频(或幻灯片)文件,您可以获取从中下载的URL,删除文件名,并添加必要的额外路径组件以制作字幕URL,然后下载该字幕文件 - 和这就是我的应用程序所做的。

我的模特

虽然我最初设想了一个双层模型,但我最终得到了一个单一的平面列表,所以我现在只使用大纲视图作为普通表视图 - 没有任何项目有任何子项。

我的商品是下载来源,每个商品都有以下属性:

  • 视频文件名
  • 当前字幕文件索引(从0开始)
  • 当前下载进度分数(每个字幕文件从0到1)
  • 下载的所有字幕文件(bool),此后称为“完成”

当我将视频文件提供给我的应用时,它会创建一个下载源,依次生成每个字幕文件的远程URL。我的应用程序下载每个字幕文件,随时更新下载源的状态。

我的应用无法知道有多少字幕文件;它只知道它们已被编号。因此,当它获得404时,它知道它已经下载了该视频文件的所有字幕文件,因此它将下载源标记为完成并继续下一个下载源(如果有的话)。

如何填充大纲视图

我的窗口控制器是我的大纲视图的数据源和委托。

大纲视图是基于视图的。在行视图中,四个单元视图中的三个绑定到其对象值的属性:

  • 第一列中的文本字段绑定到视频文件名。
  • 第二列中的文本字段绑定到当前字幕文件索引。
  • 第三列中的进度条绑定到进度分数。

第四列包含一个图像视图,这就是困难的来源。

因为我不想用“doneImage”属性污染我的模型(我觉得这是控制器业务),我让控制器在返回单元格视图时设置图像视图的图像:< / p>

- (NSView *) outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
    NSTableCellView *cellView = [outlineView makeViewWithIdentifier:tableColumn.identifier owner:self];
    PRHVideoFileDownloadSource *downloadSource = item;
    cellView.objectValue = downloadSource;
    if ([tableColumn.identifier isEqualToString:@"done"]) {
        NSLog(@"Source %@ is done: %@", downloadSource, downloadSource.complete ? @"true" : @"false");
        cellView.imageView.image = downloadSource.complete ? [NSImage imageNamed:@"Done"] : nil;
    }
    return cellView;
}

问题

最初,这很好用。 如果我取出测试模型对象是否完成的条件,则完成图像显示(因此我知道正在复制图像,它是一个有效的图标,列的标识符设置正确,等)。

但是,在适当的条件下,即使在下载源变为完成后,图像也不会出现。

你可以看到我添加了一个NSLog。这只出现一次(每行):

2013-07-22 15:46:18.028 WWDC Subtitles Fetcher[7980:1307] Source <PRHVideoFileDownloadSource 0x7fd6f533d340 "404-Advances in Objective-C.pdf"> is done: false
2013-07-22 15:46:18.035 WWDC Subtitles Fetcher[7980:1307] Source <PRHVideoFileDownloadSource 0x10b372190 "405-Interface Builder Core Concepts-SD.mov"> is done: false

通过绑定到单元格视图objectValue的属性来填充的单元格都可以正常工作。仅此内容视图未绑定的单元格不会更新。

我尝试了什么

如上所述,我在调用outlineView:viewForTableColumn:item:时尝试过记录。每行只调用一次;再也不会了。

所以,也许我需要提示它重新加载那些行,对吧?我在标记下载源的行之后立即添加了reloadItem:消息。没有骰子 - 它肯定已到达(我有另一个错误,因为修复后,当我这样做时导致异常),但是大纲视图没有采取提示并要求我重新创建/更新此视图。

我还尝试将图片视图绑定到单元格视图的objectValue并实现outlineView:objectValueForTableColumn:byItem:

//Revised outlineView:viewForTableColumn:item: that doesn't set the cell view's objectValue
- (NSView *) outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
    NSTableCellView *cellView = [outlineView makeViewWithIdentifier:tableColumn.identifier owner:self];
    return cellView;
}

//Return the Done image for the “done” column; return the Download Source for all other columns (whose cells' content views are bound to properties of the Download Source)
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
    PRHVideoFileDownloadSource *downloadSource = item;
    if ([tableColumn.identifier isEqualToString:@"done"]) {
        NSLog(@"Source %@ is done: %@", downloadSource, downloadSource.complete ? @"true" : @"false");
        return downloadSource.complete ? [NSImage imageNamed:@"Done"] : nil;
}
    return downloadSource;
}

虽然这更干净,但我认为我会保留它,但它并没有解决问题 - objectValueForTableColumn:byItem:方法同样只被调用一次,尽管reloadItem:,因此没有机会将图像分配为该单元格的新objectValue

我需要什么

我需要一种方法(有效)告诉大纲视图“这个特定的行已经改变了;请更新其objectValue s - 或者更好的方法,告诉它该行中的特定单元格已更改。

1 个答案:

答案 0 :(得分:1)

不是返回“完成”列的复选标记图像以及其他列的下载源,而是返回所有列的下载源。然后使用NSNegateBoolean值转换器将图像视图的“隐藏”绑定绑定到下载源的“完整”属性。当模型触发KVO通知时,这将允许图像显示或隐藏自身,因此您不必刷新项目并希望以您希望的方式更新内容。