スタックトレースからは、競合状態、より具体的には、おそらく辞書内のstrong
プロパティまたは変数のデータ競合のみがわかります。クラッシュがメインスレッドで発生しているので、私の最初の推測は、バックグラウンドスレッドでアクセスすべきではないバックグラウンドスレッドでAPIを使用したことです。
- なぜデータレースだと思いますか?
- 競合状態のためにコアデータコードがメインスレッドでクラッシュする可能性が最も高い理由は何ですか?
- このバグを修正するためのいくつかの提案。
なぜデータレースだと思いますか?
objc_retain
でクラッシュが発生するためです。これは単なる経験です。オブジェクトを保持することによるクラッシュが発生する10のケースのうち9つでは、データ競合によるものです。他の1つのケースでは、原因は手動でメモリ管理が間違っていたことでした。より詳細な情報が必要な場合は、objc_storeStrong()のソースを参照することができます。
第二に、Concurrency section in the Core Data Referenceはこの情報の面白い作品を持っています
NSMainQueueConcurrencyTypeは、アプリケーション・インターフェースで使用するための、具体的であり、唯一のアプリケーションのメインキューに使用することができます。
NSPrivateQueueConcurrencyType構成は、初期化時に独自のキューを作成し、そのキューでのみ使用できます。キューはプライベートでNSManagedObjectContextインスタンスの内部にあるため、performBlock:およびperformBlockAndWait:メソッドを使用してのみアクセスできます。
競合状態のためにコアデータコードがメインスレッドでクラッシュする可能性が最も高い理由は何ですか?
ご質問のコードによれば、NSMainQueueConcurrencyType
を使用しているため、この「管理コンテキスト」を持つバックグラウンドキューでコアデータを使用しないでください。
私の推測では、バックグラウンドスレッドからコアデータAPIをどこかに呼び出すと思います。
このバグを修正するためのいくつかの提案。
競合状態が必ずしもクラッシュするとは限りません。このため、このようなクラッシュを容易に再現することができないことがあります。しかし、すべてが失われません。
本当にデータ競争かどうかを確認するには、完全なクラッシュレポートを参照する必要があります。クラッシュレポートでは、クラッシュしたメインスレッドのバックトレースを取得するだけでなく、クラッシュが発生した時点でプロセスの他のすべてのスレッドのバックトレースも取得します。 (単にクラッシュレポートの "CoreData"を検索してください)非常に不運な場合は、バックグラウンドスレッドにコアデータAPIが表示されません。この場合、少なくとも「autorelasepoolpop」フレームを持つスレッドが少なくとも1つは見えるはずです。バックグラウンドスタックトレース上に「CoreData」フレームがいくつか見つかった場合は、そのスタックトレース内のアプリケーションコードを指すフレームを見つけます。そこには犯人がいる。
デバッグの場合は、コアデータAPIと呼ばれる場所であれば、どこでもassert([NSThread isMainThread]);
コールをいくつか呼び出すことができます。アサーションの失敗のためクラッシュした場合、問題がどこにあるかを知ることができます。
Xcode 9を使用している場合は、新しい「メインスレッドサニタイザ」(「診断ツール」の下のスキーム設定で、「スレッドサニタイザ」も設定されているパネルと同じパネル)を試してみるとよいでしょう。 「問題を一時停止する」)。これで問題が解決しない場合は、「糸消毒剤」も試してみてください。
同時実行タイプをNSPrivateQueueConcurrencyType
に切り替えることもできます。すべてのコアデータAPIコールをperformBlock:
とperformBlockAndWait:
コールでラップするようにしてください。そうしないと、クラッシュは少なくなりますがクラッシュはさらに多くなります。これは、実際にバックグラウンドキューからコアデータを使用する必要がある場合などに使用します。パフォーマンス上の理由から。
あなたが運が良ければ、これはちょっとしたコードミスで、10分で修正できます:-)。あなたが非常に不運な場合は、アプリケーションの並行アーキテクチャが壊れているため、再設計する必要があります: - /。
これが役に立ちます。
はデータ競争のようです。 – Michael