2011-09-07 12 views
9

NSOperationの場合、[NSOperationQueue currentQueue]または[NSThread currentThread]と等価ですか?現在実行中のNSOperationを保留にする方法は?

私はかなり複雑なドメインモデルを持っています。ここでは、重い処理がコールスタックのかなり深いところで起こります。タイムリーにオペレーションをキャンセルするには、より長いループを中断したいポイントに達するまで、すべてのメソッドにパラメータとしてNSOperationを渡す必要があります。スレッドを使用して私は[[NSThread currentThread] isCancelled]を使用することができますので、NSOperationに相当するものがあれば便利だと思いますが、残念ながら一見役に立たない[NSOperationQueue currentQueue]しかありません。

答えて

3

これはお勧めできません。操作は通常、キューによってキャンセルされます。オペレーションのmain()メソッド内で、自分がキャンセルされたかどうかを定期的にチェックすることができます(ループをたどったり、コマンドのすべてのメジャーブロックの開始時など)。

キャンセル(たとえば、操作またはキューのステータスに関連付けられたUI要素)に応答するには、キー値監視(KVO)を使用して、コントローラが操作の開始、完了、およびキャンセルされたプロパティを観察するようにします)、それらのキーが更新されたときにUIの状態を(メインスレッド上に常に)設定します。 Per JeremyPのコメントによれば、KVO通知はオペレーションのスレッドから来ており、UIは(ほとんど)常にのメインスレッドで操作されるはずですので、-performSelectorOnMainThread ...メソッドを使用して実際のUIを更新する必要がありますあなたがあなたの操作についてKVOノートを変更した状態を受け取ったとき。

あなたは本当に何をしようとしていますか?つまり、なぜあなたのアプリの他の部分が現在の操作について直接知っている必要があると感じますか?

+0

-1私は怖い:
myOperation.thread = [NSThread currentThread] 

あなたはその後、 'currentOperation' メソッドを追加することができます。これのどれもうまくいきません。オペレーションのisCancelledプロパティを設定することは、オペレーションがisCancelledプロパティを定期的にチェックしない限り無効です。 KVO通知は送信された同じスレッドで受信されるため、確かにKVOは機能しません。 – JeremyP

+3

Errr ...あなたはそれを投票する前に私の投稿を読んだことがありますか?これらのプロパティを観察することは、これらのことがどう行われるかということです。状態の変化を観察した後、-performSelectorOnMainThread ...を使って、メインスレッド上で何かをする必要があります。 「これのどれもうまくいかない」というニュースは、私がいくつかのアプリを持っているので、私にとってはニュースです。また、私はキャンセルを設定*したことはありません。事実、私は具体的にキューが操作をキャンセルし、操作がこの状態を定期的にチェックして、trueの場合は動作を停止すると言いました。 –

+0

何が起こるか:キューはops - > opの投稿をキャンセルするisCancelledのKVOノート、自分自身を停止する - > Observer(あなたの一部のコントローラ)のメモが変更され、もしあれば、メインスレッドでそれを行います。毎回動作します。あなたのコントローラが別のスレッドでメッセージされているからといって、それを処理できないわけではありません。メインスレッドで何かをしなければならない場合は、すぐに進み、メインスレッド上で何かを送信してください。 –

0

キャンセルする操作をどのように知っていますか? キャンセルする時点になると、[myQueue操作]を呼び出して、キャンセルしたい操作が見つかるまで操作を進めるだけです。私はあなたが数百万の操作(または何千も)を持っていれば、これはうまくいかないかもしれないと思います。

[myQueue操作]はスレッドセーフです。キューの内容のスナップショットです。あなたはそれを意識して素早く取り消すことができます。

別の方法: NSOperationQueueはシングルトンではないので、200のジョブを持つQを作成して、そのQを取得してすべてキャンセルすることで20をすべてキャンセルすることができます。 Qをメインスレッドの辞書に格納すると、取り消したいジョブをdictから取得してすべて取り消すことができます。つまり、1000種類の操作があり、コード内で特定のタスクが不要であることがわかった時点で、その種類のQを取得し、取り消すジョブを探します。

4

いいえ、現在実行中の操作を見つける方法はありません。あなたの問題を解決するため

二つの方法:

  1. 操作がオブジェクトです。オブジェクトAとオブジェクトBとの会話が必要な場合は、AがBを参照するように手配する必要があります。それを行う方法はたくさんあります。 1つの方法は、それについて知る必要のある各オブジェクトに操作を渡すことです。もう一つは委任を使うことです。 3つ目は、操作を各メソッドまたは関数に渡すより大きな「コンテキスト」の一部にすることです。あるオブジェクトから他のオブジェクトへ参照を渡す必要があることが判明した場合は、それを最終的に使用するオブジェクトに参照を渡す必要があります。これは、コードを並べ替えることを考える上での手掛かりです。

  2. 「重い持ち上げ」メソッドは、コールチェーンを渡される値を返します。あなたの目標を達成するために、[currentOperation cancel]に電話するには、重い持ち上げの方法は必ずしも必要ではありません。実際には、戻り値を確認してただちに-isCancelledを呼び出すのではなく、すぐに終了することができるため、操作が理解できる「作業が完了しました。今すぐ停止する」という価値を戻す方が良いでしょう。それがキャンセルされたかどうかを調べる。

1

現在の操作をスレッド辞書に格納できます。終了する前にそれを取り除くことを忘れないでください。オブジェクトを作成した場合は、スレッドdictを安全に使用できます。

4

は[あなたは、次に最初の

if let operation = aQueue.runningOperations.first {} 
+0

私はそれを試してみましたが、スウィフト宣言から、[[[NSOperationQueue currentQueue] runningOperations] objectAtIndex:0]を使ってObjective-Cで呼び出されるまでのクラスを含む、非常にエレガントに動作します。 – eGanges

1

を拾うことができる

extension NSOperationQueue { 
    public var runningOperations: [NSOperation] { 
     return operations.filter {$0.executing && !$0.finished && !$0.cancelled} 
    } 
} 

あなたは、[NSOperationQueue currentQueue] &の組み合わせを使用することができる実行操作を返す迅速に拡張を思い付いNSThread currentThread]を実行します。

本質的に、currentQueueの操作をループして、currentThreadで実行中の操作を見つける必要があります。

NSOperationは、実行中のスレッドへのアクセスを提供しないため、そのプロパティを自分で追加して割り当てる必要があります。

あなたはおそらく既にNSOperationのサブクラスを作成し、メインを提供するので、そのサブクラスに「スレッド」プロパティを追加している:

@interface MyOperation : NSOperation 
    @property(nonatomic,strong) NSThread *thread ; 
@end 

すると、そのプロパティに現在のスレッドを割り当てる

あなたの「メイン」に
+(MyOperation *)currentOperation 
{ 
    NSOperationQueue *opQueue = [NSOperationQueue currentQueue] ; 
    NSThread *currentThread = [NSThread currentThread] ; 

    for(MyOperation *op in opQueue.operations) { 
     if([op isExecuting] && [op respondsToSelector:@selector(thread)]) { 
       if(op.thread == currentThread) { 
        return (op) ; 
       } 
      } 
     } 
    } 

    return nil ; 
} 
関連する問題