1

描画/ペイントは常に GUI スレッドで行う必要があります。そうしないと、デッドロックが発生する可能性があります!...

呼び出しが iOS のメイン スレッドから安全でないペイントを引き起こす可能性があるかどうかをどのように判断しますか?

問題は、メインスレッドにないこのようなスタックを取得することです...

#19 0x02a788d2 in -[CALayer drawInContext:]
#20 0x02a784b0 in backing_callback
#21 0x02a77d52 in CABackingStoreUpdate
#22 0x02a7701d in -[CALayer _display]
#23 0x02a76ac7 in CALayerDisplayIfNeeded
#24 0x02a689e1 in CA::Context::commit_transaction
#25 0x02a68732 in CA::Transaction::commit
#26 0x02aa604f in CA::Transaction::release_thread
#27 0x918b21e3 in _pthread_tsd_cleanup
#28 0x918b1df6 in _pthread_exit
#29 0x0018bbf2 in +[NSThread exit]
#30 0x0018bb5b in __NSThread__main__
#31 0x918a981d in _pthread_start
#32 0x918a96a2 in thread_start

これを引き起こすかどうかはどうやってわかりますか?何か間違ったことをしたときに自分自身に警告するためのデバッグのヒントやその他のテクニックはありますか?

4

2 に答える 2

1

描画の原因となる可能性のあるものを操作する前に、メインスレッドにいることを確認する必要があります。

たとえば、切り離されたスレッドからUITableViewをリロードする場合は、次を呼び出す必要があります。

[myTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];

また、描画を引き起こす可能性のあるステートメントがいくつかある場合は、描画を実行し、メインスレッドで実行されることを確認する別のメソッドを使用できます。

- (void) asyncDoSomeStuff {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // Do your stuff
    ...

    // Update UI
    [self performSelectorOnMainThread:@selector(refreshGUI) withObject:nil waitUntilDone:NO];

    [pool release];
}

- (void) refreshGUI {
    [myTableView reloadData];
    [myImageView setImage:[UIImage imageNamed:@"blabla.png"]];
    ...
}

最後に、描画を実行する特定のメソッドを呼び出すスレッドがわからない場合は、メソッドの最初に次のステートメントを追加できます。これにより、メソッド全体がメインで実行されるようになります。スレッド:

- (void) myMethod {
    if(![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(myMethod) withObject:nil waitUntilDone:NO];
        return;
    }

    // Do your stuff
}

そうでなければ、メインスレッドの外で描画が実行されることを検出する解決策はないと思います。たとえば、UIKitに関連するものはすべてメインスレッドで発生する必要があります。

于 2011-02-26T09:48:52.573 に答える
1

setNeedsDisplay が自動的に描画をメイン スレッドのキューに入れていないことに驚きました....

バックグラウンド スレッドから performSelectorOnMainThread:@selector(setNeedsDisplay) を使用すると、上記のようなスタックが生成されず、必要に応じてメイン スレッドにペイントされるようです。

バックグラウンド スレッドから setNeedsDisplay を呼び出すときに、メイン スレッドで再描画をキューに入れないのには十分な理由があるのか​​もしれません。すべてのコードを調べて、setNeedsDisplay がメイン スレッドから呼び出されるようにするか、UIView:setNeedsDisplay のカテゴリを作成して、setNeedsDisplay を呼び出す前に現在のスレッドがメイン スレッドかどうかを確認できるかどうかを検討しています。メインスレッドで setNeedsDisplay を再実行します。

免責事項...これがどのように機能するかを読んでいませんでした。テストでこれを見つけました。

于 2010-09-03T22:25:03.303 に答える