2

I'm trying to create a NSOperationQueue and add a NSOperation to it. Later I wan't to check if the queue is running and maybe abort it. All of that is supposed to be called from within different functions. What's the best approach to do this? I would be glad for a code example. Thanks!

Linus
  • 4,643
  • 8
  • 49
  • 74
  • 1
    It doesn't really answer your question but Grand Central Dispatch offer global queues out of the box. – gcamp May 15 '12 at 15:28
  • This could be the answer I was looking for. Thank you very much! – Linus May 15 '12 at 15:29
  • I managed to create and add a queue but I can't figure out how to cancel a task in the queue. – Linus May 15 '12 at 16:51
  • That's one of the caveats of GCD. http://stackoverflow.com/questions/5449469/can-you-use-cancel-iscancelled-with-gcd-dispatch-async – gcamp May 15 '12 at 18:15

2 Answers2

7

I would create an operation queue that's managed by a singleton.

First, create your singleton class. It will provide access to the NSOperationQueue. Let's call the singleton MyGlobalQueueManager.

It will have an ivar called myGlobalQueue:

@property (nonatomic) NSOperationQueue* myGlobalQueue;

In the .m file of MyGlobalQueueManager, create a fairly standard init method that will set up the operation queue:

- (id)init
{
    self = [super init];
    if (self)
    {
        myGlobalOperationQueue = [[NSOperationQueue alloc] init];
    }
    return self;
}

Now, the method that provides itself as a singleton. Again, this is pretty standard stuff:

 + (MyGlobalQueueManager *)sharedInstance
{
    static MyGlobalQueueManager *sharedInstance = nil;
    static dispatch_once_t isDispatched;

    dispatch_once(&isDispatched, ^
                  {
                      sharedInstance = [[MyGlobalQueueManager alloc] init];
                  });

    return sharedInstance;
}

Let's access that queue from wherever you want to use it:

MyGlobalQueueManager* myGlobalQueueManager = [MyGlobalQueueManager sharedInstance];
NSOperationQueue *myGlobalQueue = myGlobalQueueManager.myGlobalOperationQueue;

You can then add operations to that queue as you fancy.

How to know if anythings queued?

NSUInteger count = [myGlobalQueue operationCount];

How to abort? Cancel everything as follows:

[myGlobalQueue cancelAllOperations];

Cancelling of course depends on the operations. If you're writing custom NSOperation classes, you'll need to handle that yourself.

I find NSOperation and NSOperationQueue to be fairly easy to use and quite straightforward.

A great document to read for all this is the Concurrency Programming Guide. Specifically, have a look at Operation Queues

Max MacLeod
  • 26,115
  • 13
  • 104
  • 132
  • Hey @Max MacLeod if I have two uicontrollers and in first in viewWillDisappear call function cancelAllOperations on Singleton's Queue will it make effect on NSOpearation that I start in 2nd viewcontroller's viewdidload where first is pushing 2nd by navigation controller? – Łukasz Szpyrka Jul 23 '14 at 13:48
  • 1
    In that case I would have a queue in each view controller. Otherwise it becomes more complicated. Have a look at the MVCNetworking sample project provided by Apple. It demonstrates a network manager singleton that operates three or four different queues. – Max MacLeod Jul 23 '14 at 14:32
2

An easier way to do it is to make a "globally visible" function. AKA, declare it in a public header:

extern NSOperationQueue * SharedQueue();

and define it within your compilation "unit" - but outside any @implementation.

NSOperationQueue *SharedOperationQueue()
{
  static NSOperationQueue * _SharedQueue = nil;
  return _SharedQueue ?: ^{ _SharedQueue = NSOperationQueue.new;
                            _SharedQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;
                     return _SharedQueue;
  }();
}

As a little bonus.. #define it with an "alias".. and you can REALLy abuse it!

#define MY_SOQ SharedOperationQueue()

[MY_SOQ addOperationWithBlock:^{ /* GO CRAZY */ }];
Alex Gray
  • 16,007
  • 9
  • 96
  • 118