2

我的应用

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

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

我的模型

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

我的项目是下载源,每个项目都有以下属性:

  • 视频文件名
  • 当前字幕文件索引(从 0 开始)
  • 当前下载进度分数(每个字幕文件从 0 到 1)
  • 所有已下载的字幕文件 ( bool),以下简称“完成”</li>

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

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

大纲视图的填充方式

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

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

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

第四列包含一个图像视图,这就是困难所在。

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

- (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”——或者,更好的方法是告诉它该行中的特定单元格已更改。

4

1 回答 1

1

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

于 2013-07-24T03:20:23.707 回答