0

次のコードを使用して、Twitter でアプリを認証しようとしています: pastebin

ただし、(無駄?) ループ行 23ff を削除すると、

for (ACAccount *acc in arrayOfAccounts) {
    [acc accountType].identifier;
    //Otherwise the identifier get lost - god knows why -__-
}

でさらに実行されると、acc.type は (null) になります AccountHandler checkAccountOf:acc。ループをそのままにしておくと、タイプが正しく設定されます。私がブロックに入ってからメインキューに移動するという事実に関係していると確信していますが、何か間違ったことをしているのだろうか? このループは、私がしなければならないはずの sth のようには見えません。

似たようなことがここで起こりました。

4

1 に答える 1

4

ACAccounts はスレッドセーフではありません。それらが発生したスレッドでのみ使用する必要があります。この目的のために、「スレッド」を「キュー」と読むことができます。

私はそれに関する正式なドキュメントを見たことはありませんがNSLog、アカウントを持っている場合は、それがコア データ オブジェクトであり、コア データ オブジェクトのスレッド セーフの欠如が十分に文書化されていることがわかります。

具体的な動作は、Core Data オブジェクトが障害になる可能性があるということです。つまり、保持しているのはオブジェクトへの参照であり、実際のオブジェクトではありません。プロパティにアクセスしようとすると、オブジェクトがメモリに読み込まれます。

その下で Core Data が行っていることは、オブジェクトが実際に必要であることがわかるまで、メモリ内に物事をキャッシュし、エラーを返すことです。そのキャッシュの効率的な調整により、オブジェクトを調整する Core Data オブジェクトの個々のインスタンスが 1 つのスレッドに制限されます。

オブジェクトをメモリに入れるアクションを間違ったスレッドで実行した場合 (これは、identifierここにアクセスしたときに発生することです)、動作は未定義です。結果が得られるnilか、アプリケーションがクラッシュする可能性があります。

(余談: コア データがこのように機能する理由は、オブジェクト グラフが格納されているため、おそらく数千の相互接続されたオブジェクトであり、他のオブジェクトのグループと同じようにトラバースできます。ただし、通常はコストを支払いたくありません。使用する情報の小さなサブセットにアクセスするためだけに、それらのすべてをメモリにロードすることに関連しているため、遅延ロード中に通常のObjective-Cインターフェースを提供する方法が必要です)

リンクしたコードは、キュー ホッピングの前に、オブジェクトがキャッシュ内にあり、したがってメモリ内にあることを確認することで、その問題を回避します。したがって、「ストアからのフェッチ」ステップは正しいキューで発生します。ただし、 Core Data が適用しようとしているロジックに応じて、オブジェクトがメモリ内からフォールトに戻る可能性があるため、コードは完全に安全ではありません。

著者は明らかに、Apple 側で何らかのバグを発見したと考えています。彼らはそうではなく、スレッドセーフではないものをスレッドセーフであると想定し、テストでたまたま機能した未定義の動作に依存する方法を見つけただけです。

話の教訓: アカウント自体を 1 つのスレッドに保持します。アカウントのプロパティで何らかの処理を行いたい場合は、関連するプロパティ自体を基本的な Foundation オブジェクトとして収集し、それらをポストします。

于 2012-12-08T00:07:32.787 に答える