0

私の問題を最初から説明したいと思います。UIWebViewでアプリを作成しています。また、ユーザーがアプリを使用している瞬間の画面をキャプチャし、その画像配列を使用してビデオを作成しています。

画面のスクリーンショットを取得するために NSTimer を使用しています。私はうまくいきましたが、1つの問題がありました。それは、ユーザーがWebページのスクロールを開始したとき、またはユーザーが画面にタッチしたままNSTimerが一時停止し、タッチを離した後、NSTimerが続行したときでした。

これは、画面のスクリーンショットを取得するために使用される私の NSTimer です。

assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
                                                    target:self
                                                  selector:@selector (writeSample)
                                                  userInfo:nil
                                                   repeats:YES];

私はこの問題をグーグルで検索しましたが、ほとんどの人が私と同じ問題を抱えていました。そのため、彼らはその答えを見つけました。それは NSRunLoop を使用することです。彼らは、NSTimerの一時停止を停止すると言いました。

そこで、NSRunLoop を使用し、NSTimer を NSRunLoop に追加しました。これを実行した後のコードを次に示します。

NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
                                                    target:self
                                                  selector:@selector (writeSample)
                                                  userInfo:nil
                                                   repeats:YES];

[runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
[runLoop run];

このコードはうまく機能し、NSTimer の一時停止を停止しませんでした。しかし、NSRunLoop を使用した後、私のアプリは本当に遅くなりました。また、WebページをWebViewにロードするのに多くの時間がかかり、スクロールも非常に遅くなりました。

それで、もう一度グーグルで検索を始めたところ、問題が見つかりました。それがメインスレッドで行われているすべてのことであり、iPhoneはすべてのことを同時に処理できません。そのため、NSThread を使用して問題を解決することをお勧めします。そこで、NSThread を作成し、プロセスをカスタム スレッドにアタッチしました。

NSThread を適用した後のコードは次のとおりです。

    [NSThread detachNewThreadSelector:@selector(launchTimer) toTarget:self withObject:nil];

 -(void)launchTimer{


    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f/24.0f
                                                        target:self
                                                      selector:@selector (writeSample)
                                                      userInfo:nil
                                                       repeats:YES];
 
    [runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
    [runLoop run];

 }


-(void) writeSample{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    //did some coding here to take screen shot
    [pool release];
}

これにより、アプリの速度低下の問題が永久に解決され、アプリは非常にスムーズに再び実行されますが、現在深刻な問題が発生しています。それは私が推測するスレッドを使用しているために起こっています。カスタム スレッドとメイン スレッドが競合し、アプリがクラッシュします。その理由をグーグルで検索しました。この種の問題に関連するいくつかの質問を見つけ、何人かの人々がそれらに答えて、メイン スレッドで UI の変更を行う必要があると言いました。また、UIWebView WebThread はメイン スレッドで実行する必要があります。

これらは私が得ているいくつかのエラーレポートです。

ここに画像の説明を入力

ここに画像の説明を入力

これらのエラーは、スレッドの競合のようなものです。しかし、私はこの問題を解決する方法がわかりません。Web ビューやマップを持たないネイティブ アプリに自分のコードを使用しました。そのため、クラッシュすることなくうまく機能します。しかし、これを WebView または Map がクラッシュしているアプリに使用すると、このエラーが発生します。

私はここで非常に困っています。誰かがスレッドを処理するためのアイデアやサンプルコードを提供したり、スレッドの優先順位を処理したり、NSThreads を使用せずに NSTimer と NSRunLoop を使用したり、NSThread を使用せずにアプリの遅さを克服したりできる場合、答えは次のとおりです。とてもとても助かりました。すぐにご連絡をお待ちしております。

ありがとう。

4

2 に答える 2

0

My guess is the code that you wrote to capture screen shots is causing the problem. A simple test would be to comment out all the code in the writeSample method and see if the app still crashes. I say this because you are right that all UI related tasks should work in the Main Thread at all times.

I would suggest to use a separate thread for timer so that your timer isn't paused and then from the writeSample method force the screen capture code to run on the main thread.

Hope this helps

于 2012-12-12T11:17:44.303 に答える
0

最初に:

タイマーを使用するとすぐに、実行ループで作業しています —リファレンスから簡単にわかるように:

タイマーは実行ループと連携して機能します。

(それは第 2 段落の最初の文です)

それを邪魔にならないように、あなたの症状に:

  • 画像をキャプチャしてスレッドをブロックすると、スレッドが途切れます。

これは驚くべきことではありません。

  • そのスレッドから作業を移動すると、最初のスレッドの負担が解放されます。

ショッキングですね!

同期の問題 (クラッシュ) の原因となるコードをまったく示していないことを考えると、この皮肉な回答が、私が提供できるすべての助けとなります。

それと、上でリンクしたドキュメントを読んで理解するためのヒント…</p>


編集

私はちょうどこれを言及するのを忘れていました:

NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
assetWriterTimer = [NSTimer scheduledTimerWithTimeInterval:blablabla];
[runLoop addTimer:assetWriterTimer forMode:NSRunLoopCommonModes];
[runLoop run];

あまり意味がありません…</p>

-scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:

新しい NSTimer オブジェクトを作成して返し、デフォルト モードで現在の実行ループにスケジュールします。

(これは素晴らしいドキュメントでも説明されています。)

要するに、自分のプライベート スレッドを使用している場合は、デフォルト モードで十分です。ただし、実行ループが実際に実行されていることを確認する必要があります。

これは実際にはそのコード スニペットの最後の行によって実現されますが、タイマーがキャンセルされるまでメソッドが戻らないという事実上の原因になります…</p>

于 2012-12-13T13:14:50.230 に答える