マイアプリ
私のアプリの目的は、WWDC ビデオの字幕ファイルをダウンロードすることです。字幕は、「fileSequence0.webvtt」、「fileSequence1.webvtt」などの名前の WebVTT ファイルとして、ビデオとスライド ファイルがあるディレクトリのグランド サブディレクトリにあります。
WWDC ビデオ (またはスライド) ファイルがある場合は、ダウンロード元の URL を取得し、ファイル名を削除し、必要なパス コンポーネントを追加して字幕 URL を作成し、その字幕ファイルをダウンロードできます。アプリが行います。
私のモデル
当初は 2 層モデルを想定していましたが、最終的に 1 つのフラットなリストにたどり着いたので、現時点ではアウトライン ビューを単純なテーブル ビューとして使用しているだけです。アイテムには子がありません。
私のアイテムはダウンロード ソースであり、それぞれに次のプロパティがあります。
- 動画ファイル名
- 現在の字幕ファイルのインデックス (0 から開始)
- 現在のダウンロード進行状況の割合 (字幕ファイルごとに 0 から 1 に進みます)
- ダウンロードされたすべての字幕ファイル (
bool
)、以降「完了」と呼びます</li>
動画ファイルをアプリにフィードすると、各字幕ファイルのリモート URL を順番に生成するダウンロード ソースが作成されます。私のアプリは各字幕ファイルをダウンロードし、ダウンロード ソースの状態を更新します。
私のアプリは、字幕ファイルがいくつあるかを知る方法がありません。それが知っているのは、それらが番号付けされているということだけです。したがって、404 を取得すると、そのビデオ ファイルのすべての字幕ファイルをダウンロードしたことを認識し、そのダウンロード ソースを完了としてマークし、次のダウンロード ソース (存在する場合) に進みます。
アウトライン ビューの設定方法
ウィンドウ コントローラーは、アウトライン ビューのデータ ソースであり、デリゲートです。
アウトライン ビューはビューベースです。行ビュー内では、4 つのセル ビューのうち 3 つがオブジェクト値のプロパティにバインドされています。
- 最初の列のテキスト フィールドは、ビデオ ファイル名にバインドされています。
- 2 列目のテキスト フィールドは、現在の字幕ファイル インデックスにバインドされています。
- 3 番目の列の進行状況バーは、進行状況の割合にバインドされています。
4 番目の列には画像ビューが含まれており、ここで問題が発生します。
モデルを "<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;
}
問題
最初は、これでうまくいきます。モデル オブジェクトが完了したかどうかをテストする条件を取り除くと、Done 画像が正常に表示されます(したがって、画像がコピーされていること、有効なアイコンであること、列の識別子が正しく設定されていることがわかります)。
しかし、その状態では、ダウンロード ソースが完了した後でも、画像は表示されません。
NSLog を追加したことがわかります。これは (行ごとに) 1 回だけ表示されます。
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:
が呼び出されたときにログを記録してみました。行ごとに 1 回だけ呼び出されます。二度と。
ですから、それらの行をリロードするためにキューを入れる必要があるのではないでしょうか? 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
ことを伝える方法です。