- My First Browser-
プログレスバーを表示する
ここまででとりあえずHTML を読み込めるようになったけど、実際に動かしてみる
と、あれっ?と、思うかもしれない。というのもURL を入れても、しばらくは無反応
だからだ。裏で読み込みが始まってから、実際にレンダリング画像を表示するまで、間
がある。そこで、読み込み状態を表示するための、プログレスバーを追加しよう。
6.1 WebResourceLoadDelegate
読み込み状態を知るには、これもまたデリゲートを使うんだ。
WebResourceLoadDelegate というデリゲートを使うと、テキストや画像といっ
た、リソースを読み込んでいる最中の状態を知ることができる。
6.1.1 リソース識別子
ところで、リソースとは一体なにか?それは、HTML で示されているテキストや画
像のことなんだ。通常、HTML で使われるリソースはホスト上の1 つのファイルで、
それはそれぞれのURL で表現される。たとえば、メインのHTML ファイルである
index.html、タイトル画像であるtitle.jpg、というようにね。
だけど、実際にHTML を読み込みはじめると、リソースは途中でURL が変わる可
能性があるんだ。たとえば、URL がリダイレクトされるように設定されていると、リ
ソースのURL は変更される。これをWebKit では、読み込みのセッションを始めた
ら、URL が変更したとしても同一のリソースとしてみなすんだ。ということは、リ
ソースを区別するために、URL によらないユニークな識別子を設定してやる必要があ
る。これを、ユーザが設定することになるんだ。WebResourceLoadDelegate のた
めのメソッド、webView:identifierForInitialRequest:fromDataSource: が
これを行う。
WebKit/WebResourceLoadDelegate.h
- (id)webView:(WebView*)sender
identifierForInitialialRequest:(NSURLRequest*)request
fromDataSource:(WebDataSource*)dataSource;
このメソッドは、引数としてWebView と、リソースの初期のURL が渡される。こ
のURL は、リソースを読み込んでいる最中に、変更される可能性があるので注意。
で、このメソッドの返り値として、リソースの識別子を返すんだ。たとえば、このメ
ソッドが呼び出された順に、シーケンシャルな整数値を返す、っていう実装が考えられ
る。
(sample)
- (id)webView:(WebView*)sender
identifierForInitialRequest:(NSURLRequest*)request
fromDataSource:(WebDataSource*)dataSource
{
// リソース識別子として、resourceCount の NSNumber を作成します
NSNumber* number;
number = [NSNumber numberWithInt:resourceCount++];
return number;
}
新たなリソースの読み込みが始まる毎にこのメソッドが呼び出されるので、これでユ
ニークな識別子を作ることができるんだ。これは、このメソッドが呼び出された回数を
数えておけば、読み込まれるリソースの数を知ることができる、っていうことも意味し
てるよ。
6.1.2 読み込みの成功と失敗
リソースの読み込みが成功したら、
webVeiew:resource:didFinishLoadingFromDataSource: が呼び出されるんだ。
WebKit/WebResourceLoadDelegate.h
- (void)webView:(WebView*)sender
resource:(id)identifier
didFinishLoadingFromDataSource:(WebDataSource*)dataSource;
引数として、ユーザが設定したリソース識別子が渡されるので、どのリソースの読み
込みが終わったか、知ることができる。
失敗した場合は、
webView:resource:didFilaLoadingWithError:fromDataSource: だ。
WebKit/WebResourceLoadDelegate.h
- (void)webView:(WebView*)sender
resource:(id)identifier
didFailLoadingWithError:(NSError*)error
fromDataSource:(WebDataSource*)dataSource;
このメソッドにも、同じくリソース識別子が渡される。失敗の原因は、
WebFoundation で定義されているNSError を見ることで分かるよ。
この2 つのメソッドを使えば、いまどれだけの数のリソースが読み込まれたか、ま
たは失敗したか、が分かるんだ。これで、プログレスバーが作れるぜ。
6.2 実装
じゃ、実際に作ってみよう。まず、nib ファイルを編集して、レイアウトを変更しよ
う。これは、前回のプロジェクトの続きとして説明するよ。
■プログレスバーのためのnib ファイルの編集
1. MyDocument.nib を開く。MyDocument.nib をダブルクリックして、Interface
Builder を立ち上げてくれ。
2. ウィンドウに、プログレスバーとテキストフィールドを追加する。ウィンドウを開
いて、プログレスバーを置くためのスペースを作ろう。どこでもいいんだけど、
WebView を少し小さくして、下の方に配置することにしてみた。ここに、読み込み状
態を示すプログレスバーと、文字で示すためのテキストフィールドを追加する。デキス
トフィールドには、'3 of 5' というように、いくつリソースを読み込んだかを表示する
ようにしよう。下の図のように配置してくれ。

図6-1 ウィンドウのレイアウト
ここでは、プログレスバーの最大値は1.0 にした。また、テキストフィールドは初
期設定の文字列を消すと、見づらくなるので注意。
3. MyDocument にアウトレットを追加する。Classes タブに移動して、
MyDocument クラスを選択してくれ。ここに、プログレスバーとテキストフィールド
を指し示すためのアウトレットを追加する。それぞれ loadProgressBar、
loadStatusTextField という名前にしよう。

図6-2 MyDocument のアウトレット
4. アウトレットを接続する。Instances タブに戻って、File's Owner アイコンを選択
してくれ。そこから、Ctrl キーを押しながらドラッグする。すると、線が引き出され
るので、新しく追加されたプログレスバーとテキストフィールドにつなごう。それぞ
れ、アウトレット laodProgressBar と loadstatusTextField に「Connect」してく
れ。
ここまでできたら、セーブしてProject Builder に戻ろう。
■ソースコードの編集
5. MyDocument.h を編集する。まず、Interface Builder での変更に対応するため
に、アウトレットを追加しよう。loadProgressBar とloadStatusTextFiled という
インスタンス変数を追加する。
さらに、リソースの数を数えるカウンタのためのインスタンス変数を追加しよう。プ
ログレスバーを表示するために必要な情報は、読み込まれるリソースの数と、実際に読
み込まれたリソースの数だ。WebKit では、読み込まれたリソースの数を、成功した読
み込みと失敗した読み込みに分けることができる。だから、それぞれに対応する、3 つ
のインスタンス変数を追加しよう。こんな感じにしてくれ。
MyFirstBrowser/MyDocument.h
@interface MyDocument : NSDocument
{
IBOutlet id webView;
IBOutlet id urlTextField;
IBOutlet id loadStatusTextField;
IBOutlet id loadProgressBar;
/* 読み込むリソースの数 */
int resourceCount;
/* 読み込みに成功したリソースの数 */
int resourceCompletedCount;
/* 読み込みに失敗したリソースの数 */
int resourceFailedCount;
}
6. MyDocument.m を編集する。ここでやるべきことは、デリゲートの設定、カウン
タの初期化、デリゲートメソッドの実装、そしてプログレスバーの表示だ。
◆デリゲートの設定
まずは、デリゲートの設定を。これは、前と同じく、
windowControllerDidLoadNib: メソッドの中でやってやろう。次のように、
setResourceLoadDelegate: の呼び出しを追加するんだ。
MyFirstBrowser/MyDocument.m
- (void)windowControllerDidLoadNib:(NSWindowController*)windowController
{
// WebView のデリゲートを設定します
...
[webView setResourceLoadDelegate:self];
}
◆カウンタの初期化
続いて、カウンタの初期化。カウンタのためのインスタンス変数は、新しい読み込み
のセッションが始まる度にリセットしよう。それには
webView:didStartProvisionalLoadForFrame: が使える。
MyFirstBrowser/MyDocument.m
- (void)webView:(WebView*)sender
didStartProvisionalLoadForFrame:(WebFrame*)frame
{
// フレームがメインフレームの場合
if (frame == [sender mainFrame]) {
...
// リソースのカウンタをリセットします
resourceCount = 0;
resourceCompletedCount = 0;
resourceFailedCount = 0;
}
}
◆デリゲートメソッドの実装
そして、WebResourceLoadDelegate のためのメソッドを追加する。今回追加す
るのは、上で説明した3 つだ。
まず、リソース識別子を返すための webView:identifierForInitialRequest:fromDataSource:。このメソッドは識
別子を返すんだけど、同時に読み込むべきリソースの数を数えることもできる。そこ
で、このメソッドで、リソースのカウンタ resouceCount の値を1 増やそう。
MyFirstBrowser/MyDocument.m
- (id)webView:(WebView*)sender
identifierForInitialRequest:(NSURLRequest*)request
fromDataSource:(WebDataSource*)dataSource
{
// リソース識別子として、resourceCount の NSNumber を作成します
NSNumber* number;
number = [NSNumber numberWithInt:resourceCount++];
return number;
}
次に、読み込み成功の webView:resource:didFinishLoadingFromDataSource:。ここでは、成功カウン
タの resourceCompletedCount を増やす。増やしたら、後で説明するプログレス
バーを更新するための _updateResourceStatus を呼び出すんだ。
MyFirstBrowser/MyDocument.m
- (void)webView:(WebView*)sender
resource:(id)identifier
didFinishLoadingFromDataSource:(WebDataSource*)dataSource
{
// リソース読み込み完了カウントを増やします
resourceCompletedCount++;
// リソース読み込み状態を更新します
[self _updateResourceStatus];
}
3 つ目は、読み込み失敗のための webView:resource:didFailLoadingWithError:fromDataSource:。同じよう
に、失敗カウンタを増やして、プログレスバーを更新する。
MyFirstBrowser/MyDocument.m
- (void)webView:(WebView*)sender
resource:(id)identifier
didFailLoadingWithError:(NSError*)error
fromDataSource:(WebDataSource*)dataSource
{
// リソース読み込み失敗カウントを増やします
resourceFailedCount++;
// リソース読み込み状態を更新します
[self _updateResourceStatus];
}
◆プログレスバーの表示
最後のメソッドは、プログレスバーとテキストフィールドを更新するための、_updateResourceStatus だ。プログレスバーに設定する値は、リソースカウンタの
値から求めることができる。テキストフィールドに表示する文字も、同様ね。
MyFirstBrowser/MyDocument.m
- (void)_updateResourceStatus
{
// プログレスバーの設定をします
if (resourceCount == 0) {
[loadProgressBar setDoubleValue:0.0];
}
else {
double value;
value = (resourceCompletedCount + resourceFailedCount) /
(double)resourceCount;
[loadProgressBar setDoubleValue:value];
}
// リソースカウントの文字列を作成します
NSString* status;
status = [NSString stringWithFormat:@"%d of %d",
resourceCompletedCount + resourceFailedCount, resourceCount];
[loadStatusTextField setStringValue:status];
}
7. ビルドして実行する。プログレスバーが機能することを確認してくれ。

図6-3 MyFirstBrowser3 動作図
これで、読み込みのときに、変なストレスを感じないようなると思うよ。
■ここまでのプロジェクト:
MyFirstBrowser3.dmg