2009-08-17 7 views
3

ビューを更新するバックグラウンドタスクがあります。そのタスクは、-setNeedsDisplayを呼び出してビューを描画します。問題を求めるバックグラウンドタスクから-setNeedsDisplayを呼び出していますか?

これは動作します:

- (void) drawChangesTask; 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    if (pixels) { 
     drawChanges((UInt32 *) origPixels, (UInt32 *) pixels, CGBitmapContextGetBytesPerRow(ctx)/4, CGBitmapContextGetHeight(ctx), count--); 

     if (count < 0) { 
      count = 150; 
     } 
     else 
      [self performSelectorInBackground:@selector(drawChangesTask) withObject:nil ]; 

     [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO ]; 

    } 
    [pool release]; 
} 

これは動作しません:

- (void) drawChangesTask; 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    if (pixels) { 
     drawChanges((UInt32 *) origPixels, (UInt32 *) pixels, CGBitmapContextGetBytesPerRow(ctx)/4, CGBitmapContextGetHeight(ctx), count--); 

     if (count < 0) { 
      count = 150; 
     } 
     else 
      [self performSelectorInBackground:@selector(drawChangesTask) withObject:nil ]; 

     [self setNeedsDisplay]; 

    } 
    [pool release]; 
} 

誰もがなぜ知っていますか?私はそれが動作しないと言うとき、私はそれが数十回実行することを意味する、時々私はイメージの一部が上下にシフトした、または完全に空白を参照してください、そしてdeuggerはCoreGraphicsのどこかに "EXC_BAD_ACCESS"

また、自分で自動解放プールを処理しないと、エラーメッセージが漏れてしまいます。それがなぜか分からない。私のdrawChanges()は新しいオブジェクトを作成しません。ここでエラーです:

2009-08-17 11:41:42.358 BlurApp[23974:1b30f] *** _NSAutoreleaseNoPool(): Object 0xd78270 of class NSThread autoreleased with no pool in place - just leaking 

答えて

8

UIKitは、単純にスレッドセーフではありません - あなたは、メインスレッド上で制御しUIKitの更新メソッドを呼び出す必要があります。

私は、この行と思います:

[self performSelectorInBackground:@selector(drawChangesTask) withObject:nil]; 

がトラブルを引き起こしています。あなたは単に現在のスレッドでもう一度呼び出そうとしましたか?あなたが呼び出しの間に実行する実行ループが必要な場合は、使用:

[self performSelector:@selector(drawChangesTask) withObject:nil afterDelay:0.0]; 

これは、あなたがにしているメソッドの後、現在のスレッド上のメソッドを呼び出します完了し、実行ループは一度ラウンド行ってきました。

+0

はい、performSelectorInBackgroundを使わずに直接呼び出すと、runloopはdrawRectを実行して呼び出すことはできません。あなたが遅れて後でそれを呼び出すと言うことをすれば、それは奇妙なクラッシュなしで動作します。 – mahboudz

+1

これはまた、[self performSelectorOnMainThread:@selector(setNeedsDisplay)withObject:nil waitUntilDone:NO]を使用したときに動作する理由についても説明しています。 setNeedsDisplayを呼び出すperformSelectorInBackgroundは、drawChangesTaskと同じ関数/メソッドを呼び出し、drawChanges()関数はUIKitを呼び出さないことに注意してください。したがって、スレッドに敏感であるように見える唯一のものはsetNeedsDisplayであり、それをメインスレッドで実行すると問題はありません。 – mahboudz

+0

私は今、2つの解決策を持っています:performSelectorは0の遅延の後に、performSelectorInBackgroundはperformSelectorOnMainThreadによって呼び出されるsetNeedDisplayと共にです。 – mahboudz

2

問題はここにあなたが保証されているバックグラウンドスレッドのnothignから何かをあなたのUIを伝える場合のUIKitは、スレッドセーフではないということです、あなたがやりたいことはあなたのUI要素への更新を行うためにperformSelectorOnMainThreadメソッドを使用している

関連する問題