4

アプリで解決しようとしている問題に関して、一般的な客観的パターン/練習問題があります。ここでは、同様の目的 c に焦点を当てた質問/回答をまだ見つけることができませんでした。

私のアプリは、私が「レコード」と呼ぶオブジェクトの可変配列を保持しています。アプリはレコードを収集し、次の 2 つの方法のいずれかでその配列に配置します。

  1. アプリのサンド ボックス内でローカルに利用可能な SQLite データベースからデータを読み取ります。通常、読み取りは非常に高速です。
  2. Web サービスから非同期的にデータを要求し、それが完了するのを待ってから、データを解析します。読み取りは高速ですが、多くの場合そうではありません。

アプリがデータベースからの読み取り (1) と Web サービスからのデータの要求 (2) を実質的に同時に行う場合があります。(2) が終了する前に (1) が終了し、変更可能な配列にレコードを追加しても競合が発生しないことがよくあります。

ある時点で、SQLite 読み取りプロセスに予想よりも少し時間がかかり、非同期要求が終了して同じことを行うのとまったく同じ時刻にオブジェクトを可変配列に追加しようとするのではないかと心配しています。またはその逆。これらは、テストが難しいと思われるエッジ ケースですが、確実にアプリがクラッシュするか、少なくともレコードの配列に問題が発生する可能性があります。

また、レコードが変更可能な配列にマージされることも指摘しておく必要があります。例: (1) が最初に実行されて 10 レコードが返された場合、(2) が終了して 5 レコードが返された直後に、可変配列には 15 レコードすべてが含まれます。データを上書きするのではなく、結合しています。

私が知りたいのは:

  • (1) または (2) のプロセスが終了したときに、同じ可変配列インスタンスにオブジェクトを追加しても安全ですか?
  • Objective-C でこの種の処理を実装するための適切なパターン/プラクティスはありますか?
  • これには可変配列へのアクセスのロックが含まれるので、(1) オブジェクトをそれに追加しているとき (2) (1) が完了するまでオブジェクトを追加できませんか?

共有できる情報に感謝します。

[編集#1]

後世のために、この URL は NSOperations と NSOperationQueue の使用方法を理解するのに非常に役立つことがわかりました。少し古くなっていますが、それでも動作します:

http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues

また、私が解決しようとしている問題について具体的に述べているわけではありませんが、使用する例は実用的で理解しやすいものです。

[編集#2]

私は、ローカルで読み取り、必要に応じて、ローカル読み取りが終了した後に Web サービスをヒットする、danh によって提案されたアプローチを採用することにしました (とにかく高速である必要があります)。Taht 氏によると、同期の問題を完全に回避しようとしています。なんで?Appleがそう言っているので、ここに:

http://developer.apple.com/library/IOS/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW8

同期を完全に回避する

取り組んでいる新しいプロジェクトの場合、また既存のプロジェクトの場合でも、コードとデータ構造を設計して同期の必要性を回避することが最善の解決策です。ロックやその他の同期ツールは便利ですが、アプリケーションのパフォーマンスに影響を与えます。また、全体的な設計によって特定のリソース間で高い競合が発生した場合、スレッドはさらに長く待機する可能性があります。

並行性を実装する最善の方法は、並行タスク間の相互作用と相互依存性を減らすことです。各タスクが独自のプライベート データ セットで動作する場合、ロックを使用してそのデータを保護する必要はありません。2 つのタスクが共通のデータ セットを共有している場合でも、そのセットを分割する方法や、各タスクに独自のコピーを提供する方法を検討できます。もちろん、データ セットのコピーにもコストがかかるため、決定を下す前に、それらのコストと同期のコストを比較検討する必要があります。

4

4 に答える 4

2

(1) または (2) のプロセスが終了したときに、同じ可変配列インスタンスにオブジェクトを追加しても安全ですか?

絶対違う。NSArray は、残りのコレクション クラスと同様に同期されません。オブジェクトを追加および削除するときに何らかのロックと組み合わせて使用​​できますが、2 つの配列 (操作ごとに 1 つ) を作成し、両方が終了したときにそれらをマージするよりも明らかに遅くなります。

Objective-C でこの種の処理を実装するための適切なパターン/プラクティスはありますか?

残念だけど違う。あなたが思いつくことができるのは、ブール値をトリップするか、共通のコールバックで整数を特定の数にインクリメントすることです。私の言いたいことを理解するために、ここに小さな疑似コードを示します。

- (void)someAsyncOpDidFinish:(NSSomeOperation*)op {
    finshedOperations++;
    if (finshedOperations == 2) {
       finshedOperations = 0;
       //Both are finished, process
    }
}

これには可変配列へのアクセスのロックが含まれるので、(1) オブジェクトをそれに追加しているとき (2) (1) が完了するまでオブジェクトを追加できませんか?

はい、上記を参照してください。

于 2013-03-27T22:48:17.467 に答える
2

配列の変更をロックするか、メインスレッドで変更をスケジュールする必要があります。SQL フェッチはおそらくメイン スレッドで実行されているため、リモート フェッチ コードでは次のようなことができます。

dispatch_async(dispatch_get_main_queue(), ^{
    [myArray addObject: newThing];
}];

多数のオブジェクトを追加する場合、各レコードのスケジューラに新しいタスクを配置するため、これは遅くなります。その場合は、レコードをスレッド内の別の配列にまとめて、addObjectsFromArray: を使用して一時配列を追加できます。

于 2013-03-27T22:49:12.300 に答える
1

上記の適切な提案に加えて、GET と SQL を同時に起動しないことを検討してください。

[self doTheLocalLookupThen:^{
    // update the array and ui
    [self doTheServerGetThen:^{
        // update the array and ui
    }];
}];


- (void)doTheLocalLookupThen:(void (^)(void))completion {

    if ([self skipTheLocalLookup]) return completion();
    // do the local lookup, invoke completion
}

- (void)doTheServerGetThen:(void (^)(void))completion {

    if ([self skipTheServerGet]) return completion();
    // do the server get, invoke completion
}
于 2013-03-27T23:03:07.797 に答える
1

NSOperationQueue個人的には、データベース操作用とネットワーク操作用の 2 つの取得操作操作を並行して追加する傾向があります。次に、レコードを に追加するための専用のシリアル キューを用意しますNSMutableArray。これは、2 つの同時取得操作のそれぞれで、可変配列にレコードを追加するために使用されます。こうすることで、レコードを追加するためのキューが 1 つありますが、もう一方の同時キューで実行されている 2 つの取得操作から供給されます。2 つの同時取得操作がいつ完了したかを知る必要がある場合は、その同時キューに 3 番目の操作を追加し、その依存関係を 2 つの取得操作に設定します。これは、2 つの取得操作が完了すると自動的に開始されます。

于 2013-03-27T22:57:17.310 に答える