警告:このエントリは実験的な内容なので、うまく動きません。絶対に真似はしないで下さい。
困ってること
先日のこれの続きです。
イベントループがシングルスレッドだとか、その辺の概念も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