NSOperation - Forcing an operation to wait others dynamically

后端 未结 7 1848
情话喂你
情话喂你 2020-12-12 21:59

I am trying to implement an operation queue and I have the following scenario:

NSOperation A
NSOperation B
NSOperation C
NSOperation D
NSOperationQueue queue         


        
7条回答
  •  盖世英雄少女心
    2020-12-12 22:14

    Here's two ideas for you with contrived examples. I only used two operations but you could expand the concept to any number and/or nest them as needed.

    Example 1: Using Grand Central Dispatch

    GCD provides lightweight "dispatch groups", which allow you to explicitly order tasks and then wait on their completion. In this case AlphaOperation creates a group and enters it, then starts BetaOperation, whose completionBlock causes the group to be left. When you call dispatch_group_wait, the current thread blocks until the number of times entering the group is equal to the number of times leaving it (a lot like retain count). Don't forget to check the isCancelled state of the operation after any potentially long-running task.

    @interface BetaOperation : NSOperation
    @end
    @implementation BetaOperation
    - (void)main
    {
        NSLog(@"beta operation finishing");
    }
    @end
    
    @interface AlphaOperation : NSOperation
    @end
    @implementation AlphaOperation
    - (void)main
    {
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_enter(group);
    
        BetaOperation *betaOperation = [[BetaOperation alloc] init];
        betaOperation.completionBlock = ^{
            dispatch_group_leave(group);
        };
    
        [betaOperation start];
    
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
        if ([self isCancelled])
            return;
    
        NSLog(@"alpha operation finishing");
    }
    @end
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            AlphaOperation *operation = [[AlphaOperation alloc] init];
            [operation start];
        });
    
        return YES;
    }
    
    @end
    

    Example 2: Using a local NSOperationQueue

    Since you're already with working operations, another option is creating a queue as a property of AlphaOperation, then adding BetaOperation and calling waitUntilAllOperationsAreFinished on the queue. This has an added benefit in that you can easily cancel the queue's operations when AlphaOperation is cancelled, simply by overriding the cancel method.

    @interface BetaOperation : NSOperation
    @end
    @implementation BetaOperation
    - (void)main
    {
        NSLog(@"beta operation finishing");
    }
    @end
    
    @interface AlphaOperation : NSOperation
    @property (strong) NSOperationQueue *queue;
    @end
    @implementation AlphaOperation
    - (void)main
    {
        self.queue = [[NSOperationQueue alloc] init];
    
        BetaOperation *betaOperation = [[BetaOperation alloc] init];
        [self.queue addOperation:betaOperation];
        [self.queue waitUntilAllOperationsAreFinished];
    
        if ([self isCancelled])
            return;
    
        NSLog(@"alpha operation finishing");
    }
    
    - (void)cancel
    {
        [super cancel];
    
        [self.queue cancelAllOperations];
    }
    @end
    
    @implementation AppDelegate
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            AlphaOperation *operation = [[AlphaOperation alloc] init];
            [operation start];
        });
    
        return YES;
    }
    
    @end
    

提交回复
热议问题