2012-07-15 12 views
6

私はiPadアプリを開発していますが、現在はマルチスレッド化に最適なアプローチを見つけるのに苦労しています。
2つのサブビュー、ディレクトリピッカー、選択したディレクトリ内のすべての画像のサムネイルを含むギャラリーがあります。これらのサムネイルを「ダウンロード」して生成するにはかなりの時間がかかるので、マルチスレッドが必要になるため、ビューの相互作用と更新はブロックされません。Objective Cのベスト・マルチスレッド化アプローチ?

これは、私はすでに試したものです。[自己performSelectorInBackground:@selector(displayThumbnails :) withObject:currentFolder]

ユーザーの操作がブロックされなかったため、これは正常に機能しましたが、最初のフォルダがまだ読み込まれている間にユーザーが別のフォルダをタップすると失敗します。 2つのスレッドが同じビューと変数にアクセスしようとしているため、それぞれが適切に実行されています。ユーザーが別のフォルダをタップすると、現在ロード中のフォルダのdisplayThumbnailsが中止されます。私はこれを行うにはどのような方法を見つけることができませんでした。..

NSThreads
を私はこれを試みたが、第一の方法とほぼ同じ問題で苦労し、私はキャンセルする(簡単な)方法を見つけることができませんでした進行中の方法。 (はい、私は[aThread cancel]について知っていますが、スレッドを「再開する」方法が見つかりませんでした)。多分私はNSThreadをサブクラス化し、私自身のisRunningなどのメソッドを実装する必要がありますか?しかし、私が見落としているより良い方法や3番目(あるいは4番目と5番目の)オプションはありませんか?

私はこれはかなり簡単な例だと思うし、おそらくより良い解決策がサブクラス化しないとNSThreadだと思います。だから、あなたは何をしますか?あなたの意見をしてください!

+4

明らかに「GCD」としか読めない答えはありません – JustSid

+4

あなたは完全に間違っています。真剣に。 – puzzle

+0

[こちら](https://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html%23//apple_ref/doc/uid/TP40008091-CH102-SW2)を参照してください。なぜGCDがとてもクールなのか:)さらに、WWDCセッションの1つをご覧ください:) オリジナルの問題について:スレッド、GCDまたはNSOperationQueueを使用しているかどうかにかかわらず、取り消しまたは一時停止のさまざまな方法があります。私はNSOperationQueueが合理的な実装に自動的にあなたを導くので、今すぐあなたのための良い解決策になると思います。 – puzzle

答えて

6

NSOperationQueueはこの作業に適しています。

もう一つの選択肢はplain GCDですが、これまで勉強したことがない人は、「正しい方法」を実装する方法を自動的に案内するので、おそらくNSOperationQueueが良い選択です。

5

Concurrent NSOperationsを使用して、イメージをバックグラウンドでダウンロードして処理したいと考えています。これらはNSOperationsQueueによって管理されます。基本的には、これらの操作は、操作ごとに1つのイメージをフェッチし、処理し、ファイルシステムに保存し、メインスレッドのメインアプリケーションにメッセージを返します。

githubにはいくつかのプロジェクトがあります。これは、「並行」または「NSOperation」を使用してgithubを検索するだけで、これを行う方法を示すことができます。

iOSには、バックグラウンド作業を行うための優れた機能があります。グランドセントラルディスパッチ(GCD)とブロック、しかしそれらはデリゲートコールバックを使用してオブジェクトを持つことはできません - したがってNSOperation。

ブロック単位でGCDを読んでから、オープンソースのConcurrent NSOperationsコードを調べる必要があります。同時NSOperationsの使用は、ブロックを使用するのと同じくらい単純ではありません。

0

この問題を抱えていた私は、私はおそらく、このようなアプローチのために行くだろう場合:私はないんだけど(

  • シングルスレッドイメージをロードし、その結果を表示するためにメインスレッドを引き起こしGUIオブジェクトを使ってスレッドを混乱させる大きなファン)

  • 新しいディレクトリが要求されたときは...うまくいけば、管理方法によります。基本的には、メインスレッドが標準のキュー構造(条件変数と配列)を使用して、パス名を渡すことによって "このディレクトリが必要になる"ことをスレッドに伝えることができます。スレッドはイメージがロードされている間もキューをチェックし、表示されるたびに新しいディレクトリに切り替えます。

  • すべての状態を保持するディレクトリリーダーオブジェクトを作成できます。パスで索引付けされたものを辞書に格納します。新しいディレクトリが要求されたときは、そのディレクトリを最初にチェックし、このディレクトリがない場合は新しいオブジェクトを作成します。こうすることで、部分的にロードされたディレクトリは、再度必要になるまでぶら下がり、最初から起動するのではなく読み込みを続けることができます。スレッドの

擬似コード:ディレクトリローダー用として

while (forever) 
    new element = nil 
    if we have an active directory loader 
     tell directory loader to load one image 
     if false then make directory loader inactive 
     lock queue condition 
     if queue has elements 
      new element = retrieve LAST element (we aren't interested in the others) 
      empty queue 
      unlock with status "empty" 
     else 
      unlock queue 
    else 
     lock queue on condition "has elements" 
     new element = retrieve last element 
     empty queue 
     unlock with status "empty" 
    if new element != nil 
     if directory loader for new path does not exist 
      setup new directory loader for new path 
      store in dictionary 
      make it the "active" one 
     else 
      make the current one the "active" 

が、それは次のようになります。

read one image: 
    if there are still images to read: 
     read, process and store one 
     return true 
    else 
     performSelectorOnMainThread with an "update GUI" method and the image list as parameter 
     return false; 

これはただ速いスケッチです。スレッドにコードの重複があります。私が書き込んだ方法では、すべての画像を読み込んだらGUIを更新します。現在の画像リストをコピーするか、同期を追加する必要があります。

関連する問題