Skip to content

Instantly share code, notes, and snippets.

@claybridges
Created March 19, 2014 18:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save claybridges/9648377 to your computer and use it in GitHub Desktop.
Save claybridges/9648377 to your computer and use it in GitHub Desktop.
Possibly part of an answer to http://stackoverflow.com/questions/22509735.
#import <Foundation/Foundation.h>
@interface BarrierOperation : NSOperation
@end
@interface BarrierQueue : NSObject
- (void)addOperation:(NSOperation *)op;
@end
#import "BarrierQueue.h"
#pragma mark - BarrierOperation
@implementation BarrierOperation
@end
#pragma mark - BarrierQueue
@interface BarrierQueue ()
@property (nonatomic, strong) NSMutableArray *queueOfQueues;
@end
@implementation BarrierQueue
- (instancetype)init
{
if ((self = [super init])) {
_queueOfQueues = [[NSMutableArray alloc] init];
}
return self;
}
- (void)addOperation:(NSOperation *)op
{
@synchronized (self) {
if ([op isKindOfClass:[BarrierOperation class]]) {
[self addBarrierOperation:(id)op];
} else {
[[self addingQueue] addOperation:op];
}
}
}
// Queue to which operations are still being added.
// Should only be accessed w/i a synch(self) block.
- (NSOperationQueue *)addingQueue
{
if ([_queueOfQueues count] == 0) {
[_queueOfQueues addObject:[[NSOperationQueue alloc] init]];
// start?
}
return [_queueOfQueues lastObject];
}
- (void)popQueue
{
@synchronized (self) {
NSAssert([_queueOfQueues count], @"should always be one to pop");
[_queueOfQueues removeObjectAtIndex:0];
if ([_queueOfQueues count]) {
// first queue is always running, all others suspended
[(NSOperationQueue *)_queueOfQueues[0] setSuspended:NO];
}
}
}
// call only from @synchronized block in -addOperation:
- (void)addBarrierOperation:(BarrierOperation *)barrierOp
{
[[self addingQueue] setSuspended:YES];
for (NSOperation *op in [[self addingQueue] operations]) {
[barrierOp addDependency:op];
}
[[self addingQueue] addOperation:barrierOp];
// if you are free to set barrierOp.completionTask, you could skip popCallback and do that
__block typeof(self) weakSelf = self;
NSOperation *popCallback = [NSBlockOperation blockOperationWithBlock:^{
[weakSelf popQueue];
}];
[popCallback addDependency:barrierOp];
[[self addingQueue] addOperation:popCallback];
[[self addingQueue] setSuspended:NO];
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue setSuspended:YES];
[_queueOfQueues addObject:opQueue]; // fresh empty queue to add to
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment