我的应用
我的应用程序的目的是下载 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”——或者,更好的方法是告诉它该行中的特定单元格已更改。