Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use NSOperationQueue as a LIFO stack?

i need to do a series of url calls (fetching WMS tiles). i want to use a LIFO stack so the newest url call is the most important. i want to display the tile on the screen now, not a tile that was on the screen 5 seconds ago after a pan.

i can create my own stack from a NSMutableArray, but i'm wondering if a NSOperationQueue can be used as a LIFO stack?

like image 460
Padin215 Avatar asked Apr 09 '12 19:04

Padin215


3 Answers

You can set the priority of operations in an operation queue using -[NSOperation setQueuePriority:]. You'll have to rejigger the priorities of existing operations each time you add an operation, but you can achieve something like what you're looking for. You'd essentially demote all of the old ones and give the newest one highest priority.

like image 160
Ken Thomases Avatar answered Oct 21 '22 02:10

Ken Thomases


Sadly I think NSOperationQueues are, as the name suggests, only usable as queues — not as stacks. To avoid having to do a whole bunch of manual marshalling of tasks, probably the easiest thing is to treat your queues as though they were immutable and mutate by copying. E.g.

- (NSOperationQueue *)addOperation:(NSOperation *)operation toHeadOfQueue:(NSOperationQueue *)queue
{
    // suspending a queue prevents it from issuing new operations; it doesn't
    // pause any already ongoing operations. So we do this to prevent a race
    // condition as we copy operations from the queue
    queue.suspended = YES;

    // create a new queue
    NSOperationQueue *mutatedQueue = [[NSOperationQueue alloc] init];

    // add the new operation at the head
    [mutatedQueue addOperation:operation];

    // copy in all the preexisting operations that haven't yet started
    for(NSOperation *operation in [queue operations])
    {
        if(!operation.isExecuting)
            [mutatedQueue addOperation:operation];
    }

    // the caller should now ensure the original queue is disposed of...
}

/* ... elsewhere ... */

NSOperationQueue *newQueue = [self addOperation:newOperation toHeadOfQueue:operationQueue];
[operationQueue release];
operationQueue = newQueue;

It seems at present that releasing a queue that is still working (as will happen to the old operation queue) doesn't cause it to cancel all operations, but that's not documented behaviour so probably not trustworthy. If you want to be really safe, key-value observe the operationCount property on the old queue and release it when it goes to zero.

like image 41
Tommy Avatar answered Oct 21 '22 02:10

Tommy


I'm not sure if you're still looking a solution, but I've the same problem has been bugging me for a while, so I went ahead and implemented an operation stack here: https://github.com/cbrauchli/CBOperationStack. I've used it with a few hundred download operations and it has held up well.

like image 21
cbrauchli Avatar answered Oct 21 '22 02:10

cbrauchli