Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

WebKitを別のスレッドで動かしたかった(けど無理だった)

警告:このエントリは実験的な内容なので、うまく動きません。絶対に真似はしないで下さい。

困ってること

先日のこれの続きです。

イベントループがシングルスレッドだとか、その辺の概念も3年の年月を経てわかったので、HTTPでサイトを読み込む処理もうまく最適化できる気がします。もうちょっといじってみようかな。

このアプリがやりたいことは、CoralのようにWeb Kitを使ってWEBページを画像として抽出し、OpenGLのテクスチャとして利用することです。ところが、Web Kitをメインループで回すと、どうも途中で引っかかりが起こるみたいで、OpenGLレンダリングアニメーションでフレームが飛んでしまいます。

実験

そこで、Web Kitを別のスレッドで回せばいいのではと考えて動かしてみました。

まず、別スレッドを立ち上げて、そこでWeb Kitの初期化を行います。

        /* 別スレッド立ち上げはこんな感じ */
	[NSThread detachNewThreadSelector: @selector(useWebKit) toTarget:self
	                       withObject: nil];
        /* Web Kitの初期化はだいたいこんな感じ */
	dummyWindow =
	[[NSWindow allocWithZone : [self zone]] 
            initWithContentRect : NSMakeRect(0.0, 0.0, 800, 1600) 
            styleMask           : NSBorderlessWindowMask 
            backing             : NSBackingStoreNonretained 
            defer               : NO];

	dummyWebView = (WebView *) [[WebView alloc] initWithFrame: NSMakeRect(0, 0, 800, 1600)];
	[dummyWebView setFrameLoadDelegate: self];
	[dummyWebView setCustomUserAgent: @"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/412 (KHTML, like Gecko) Safari/412"];

	//WebViewの設定変更
	WebPreferences *wp = [dummyWebView preferences];
	[wp setShouldPrintBackgrounds: YES];

	//窓にセットしておく
	[[dummyWindow contentView] addSubview: dummyWebView];

NSAutoReleasePoolも作っておきます・・・略(ぉ。


で、Web Kitを動かすには NSRunLoop ってものが必要っぽいので、こいつを動かします。NSRunLoopは各スレッドに用意されてるそうです。たぶんイベントループですよね??

[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow:1]];

run を呼びたいんですが、runだとこのスレッドに制御が戻って来なくなるので、1秒後に復帰するようにしてみてます(超適当過ぎ)。

で、後は loadRequest: でdummyWebViewにリクエストを投げて結果を取得したいのですが、これだとWebKitThreadingExceptionなる例外が起き、「〜 was called from a secondary thread」と怒られます。どうやら、メインスレッド以外で動くことを拒否しているようです。

そこで禁じ手。以下のようにユーザデフォルト値を変えると、この例外の発生を止められます。

[[NSUserDefaults standardUserDefaults] setObject:@"Log" forKey: @"WebCoreThreadCheck"];

結果

突っかかりは消えました。アニメーションに突っかかりがなくなって快適。

しかし、かなりの確率で落ちますw だから、絶対このエントリを参考にしてはいけません。

考察

以下のことをまだまだ考える必要がありますねー。

  • 落ちてる原因を探る。スレッド間の同期で解決できるのか?
  • Web Kitのドキュメントとか徹底的に見る*1
  • そもそも、困ってることを解決する他の方法がないのか?

*1:Web Kitはメインスレッドでしか動かせない可能性が高いと思ってますww