1

処理するオブジェクトの配列があります。オブジェクトには以下のようなメソッドがあります

@interface CustomObject : NSObject

- (void)processWithCompletionBlock:(void (^)(BOOL success))completionBlock;

@end

各オブジェクトの処理にはさまざまな時間がかかり、結果が異なる場合があります。そして、処理自体が同時に実行されていることが知られています。実を言うと、同時操作はかなり集中的であるため、同時操作の数を制限するのは素晴らしいことです。

したがって、このオブジェクトの配列を列挙して処理する必要があります。一部のオブジェクト処理が失敗した場合、残りのすべてのオブジェクトをスキップする必要があります。そしてもちろん、すべてのオブジェクトが列挙されて処理された後、通知を受ける必要があります。

サブクラスを作成NSOperationQueueして解決する必要がありますか?NSOperationこのクラスは、これらの要件を満たすためにどのように見えるでしょうか?他にエレガントなアプローチはありますか?

4

3 に答える 3

1

これはまさにそのNSOperationために設計されたものです。ディスパッチキューははるかに低レベルのハンドラーであり、これに必要な部分の多くを構築する必要があります。もちろんそれを行うことはできますが(NSOperationQueueGCDの上に構築されています)、再発明することになりますNSOperation

ほとんどの場合、2つの方法を処理できNSOperationます。単純な場合は、を作成するだけNSBlockOperationです。もう少し複雑な場合はNSOperation、メソッドをサブクラス化してオーバーライドし、必要な処理を実行できmainます。

他のすべての操作をキャンセルするには、いくつかの方法があります。グループごとに個別の操作キューを作成できます。次に、簡単に呼び出しcancelAllOperationsてすべてをシャットダウンできます。または、関連する操作のリストを認識している別のコントローラーを使用して、それらを呼び出すこともできcancelます。

「キャンセル」とは、「見つめていなければスケジュールを立てず、見つめている場合は設定する」という意味であることを忘れないでくださいisCancelled。実行中の操作は中止されません。実行中の操作を中止する場合は、操作を定期的にチェックする必要がありますisCancelled

通常、キューが実行する同時操作の数を制限する必要があります。を使用しsetMaximimumConcurrentOperationCount:ます。

すべての操作が終了したことを確認する方法は2つあります。追加の操作(通常はBlockOperation)を作成し、それを使用addDependency:して他のすべての操作に依存させることができます。これは素晴らしい非同期ソリューションです。同期ソリューションを処理できる場合は、を使用できますwaitUntilAllOperationsAreFinished。私は通常前者を好みます。

于 2012-08-09T00:59:02.797 に答える
1

NSOperationQueueを使用して、クラスをNSOperationにします

この方法を使用して、作業をキューに入れます

- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait

作成したNSOperationサブクラスに操作キューへの参照を追加します

エラーが発生した場合は

- (void)setSuspended:(BOOL)suspend

NSOperationQueueで

于 2012-08-09T00:59:07.460 に答える
0

Ok。このアプローチをどのように処理できるかを他の人が理解できるように、私は自分のコードを共有しています。

同時スレッドの数を制限するために、 instanceの-(void)setMaximimumConcurrentOperationCount:メソッドを呼び出すことができます。NSOperationQueue

オブジェクトを反復処理して完了メカニズムを提供するために、次のメソッドを定義できます。

- (void)enumerateObjects:(NSArray *)objects
{
    // define the completion block
    NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"Update UI");
    }];

    // register dependencies
    for (CustomObject *obj in objects) {
        CustomOperation *operation = [[CustomOperation alloc] initWithCustomObject:obj];
        [completionOperation addDependency:operation]; // set dependencies for the completion block
        [_operationQueue addOperation:operation];
    }

    // register completionOperation on main queue to avoid the cancellation
    [[NSOperationQueue mainQueue] addOperation:completionOperation];
}

サブクラスの- (void)startメソッドを上書きして、カスタム操作を開始します。NSOperation

- (void)start
{
    // We need access to the operation queue for canceling other operations if the process fails
    _operationQueue = [NSOperationQueue currentQueue];

    if ([self isCancelled]) {
        // Must move the operation to the finished state if it is canceled.
        [self willChangeValueForKey:@"isFinished"];
        _finished = YES;
        [self didChangeValueForKey:@"isFinished"];
        return;
    }

    [self willChangeValueForKey:@"isExecuting"];
    // We do not need thread detaching because our `-(void)processWithCompletionBlock:` method already uses dispatch_async
    [self main]; // [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
    _executing = YES;
    [self didChangeValueForKey:@"isExecuting"];

}

- (void)mainサブクラスのメソッドを上書きしてNSOperation、カスタムオブジェクトを処理します。

- (void)main
{
    @try {
        NSLog(@"Processing object %@", _customObject);
        [_customObject processWithCompletionBlock:^(BOOL success) {
            _processed = success;
            if (!success) {
                NSLog(@"Cancelling other operations");
                [_operationQueue cancelAllOperations];
            }
            [self completeOperation];
        }];
    }

    @catch (NSException *exception) {
        NSLog(@"Exception raised, %@", exception);
    }
}

足りない部分を指摘してくれた@Robに感謝します。

于 2012-08-09T07:02:34.600 に答える