9

iOS の UIKit はスレッドセーフではありません。この事実は周知の事実と言えます。私はルールを知っています、私は注意していますが、それでも噛まれます - そして時々結果として生じるクラッシュは、UIKit への問題のバックグラウンド呼び出しから十分に離れており、問題を追跡することは楽しい経験ではありません.

この問題は簡単に解決できるようです。少なくともデバッグ機能として、UIKit クラス/メソッドがバックグラウンド スレッドから呼び出されたときに警告するようにします。私の知る限り、iOS にはそのような機能はありません。もちろん、何らかの形式のアサーションをそのような呼び出しの前に配置することで、同じ効果を手動で達成することもできますが、この解決策は最も洗練されたものではなく、さらに元の問題と同じ弱点、つまりプログラマーが物忘れしやすいという弱点があります。

誰もがよりエレガントなソリューションを持っていますか? プロジェクトでこの問題にどのように対処しますか?

(注:この質問は関連していますが、それほど明確ではありません。不思議に思っています)


更新:アンドリューの答えは、当時私が探していたソリューションですが、少なくともXcode 9の時点では、これは現在xcode/iosによって提供されていることに注意してください。たとえば、次のコードを追加します。

DispatchQueue.global().async {
        print(self.view.frame)
    }

UIView の viewDidLoad メソッドが Xcode でランタイム警告インラインを生成するには、UIView.frame をメイン スレッドからのみ使用する必要があり、メッセージがコンソールに出力されます:メイン スレッド チェッカー: バックグラウンド スレッドで呼び出される UI API: -[UIView フレーム]

4

3 に答える 3

3

このコード (プロジェクトに追加し、ARC なしでこのファイルをコンパイルするだけ) は、メイン スレッド外の UIKit アクセスでアサーションを引き起こします: https://gist.github.com/steipete/5664345

拾ったばかりのコードで多数のUIKit /メインスレッドの問題をピックアップするために使用しました。

于 2013-09-12T13:54:29.400 に答える
1

最初にシングルスレッドのアプローチを試していない限り、マルチスレッドを導入しないようにしていますが、解決しようとしている問題によって異なります。

マルチスレッドが唯一の選択肢である場合でも、私は通常、長時間実行されるバックグラウンド操作や、いくつかの無関係なタスクを実行する操作を避けます。

私の意見です。

編集

ローディングスピナーを表示しながらメインスレッドで作業を行う例:

MBProgressHUD *hud = [MBProgressHUD customProgressHUDInView:view dim:dim];
[hud show:NO];
//Queue it so the ui has time to show the loading screen before the op starts
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:block];
NSBlockOperation *finOp = [NSBlockOperation blockOperationWithBlock:^{
    [MBProgressHUD hideAllHUDsForView:view animated:NO];
}];
[finOp addDependency:blockOp];
[[NSOperationQueue mainQueue] addOperations:@[blockOp, finOp] waitUntilFinished:NO];
于 2012-12-10T18:19:54.137 に答える
0

個人的には、マルチスレッドアプローチのボックスを開くたびにperformSelectorOnMainThread:、問題が発生しないように、すべてのインターフェイスベースの呼び出しをラップし始めます。すでにメインに到達している場合、この呼び出しによって大幅な速度低下が発生することはありませんが、バックグラウンドスレッドから呼び出された場合は、安全性を確認して安心できます。

于 2012-12-10T18:55:06.807 に答える