How to use NSOperationQueue and NSOperation to periodically call serialized download tasks using a NSTimer on the background Thread
I want to execute a few Networking methods using NSOperation for each one of them, and add the the operations to an NSOperationQueue that is set on a back thread, I want the NSOperations to happen serialized.
The call that creates the NSOperation queue is called periodically, each 30 seconds using an NSTimer.
Here is a code snipped so far:
NSTimer *timer;
NSOperationQueue *bgQueue;
- (void)startdDownloadLoop{
if (![self.timer isValid]){
self.bgQueue = [[NSOperationQueue alloc] init];
self.timer = [NSTimer scheduledTimerWithTimeInterval:30.0
target:self
selector:@selector(updateDB)
userInfo:nil
repeats:YES];
}
}
- (void)updateDB{
// Next code was removed since si similar to the call `[self.bgQueue cancelAllOperations];`, as @robinkunde suggested
// for (NSOperation *operation in [self.bgQueue operations]) {
// if (operation.isExecuting) {
// [operation cancel];
// }
// }
[self.bgQueue cancelAllOperations];
self.bgQueue = [[NSOperationQueue alloc] init];
self.bgQueue.maxConcurrentOperationCount = 1;
NSBlockOperation *blockOp1 = [NSBlockOperation blockOperationWithBlock:^{
[NetworkManager downloadCars];
}];
NSBlockOperation *blockOp2 = [NSBlockOperation blockOperationWithBlock:^{
[NetworkManager downloadPartsForAllCars];
}];
NSBlockOperation *blockOp3 = [NSBlockOperation blockOperationWithBlock:^{
[NetworkManager downloadEachPathSpecs];
}];
[self.bgQueue addOperation:blockOp1];
[self.bgQueue addOperation:blockOp2];
[self.bgQueue addOperation:blockOp3];
}
The NetworkManager
methods are POST/GET methods with completion handlers, that after they finish downloading, they save the date in DB and then update the UI using a notification.
Update:
Since the confusion, I thought to post my actual question regarding the code as fallows:
1- If the execution of the NSOperationQueue
will be serial?
2 - if when I am calling the [operation cancel]
will stop the execution of the operation?
3 - If when I am calling the cancelAllOperations
and the I re-init it is the correct way of clearing the current NSOperationQueue
?
Solution 1:
1) You can set the property maxConcurrentOperationCount
on the queue to 1 to ensure serial execution.
2) This only sets the isCancelled
property on the operation. The needs to act on this change and move itself to the finished state so it can be removed from the queue.
As for your specific example: NSBlockOperation
is considered finished when all attached blocks have returned. That actually means that unless the calls to NetworkManager
are synchronous, the block returns immediately, the operation is considered finished, and the queue starts the next operation. It's entirely possible that the queue finishes before the first network operation completes. If you want to execute them one at a time, this is not the way to do it.
You could use synchronous network operations, but that still wouldn't allow you to cancel them.
Check out this answer: NSURLSession with NSBlockOperation and queues
3) This is related to 2). All cancelAllOperations
does is set the isCancelled
property on all operations. Until those operation are finished, the queue will continue to exist. Creating a new queue on the same property doesn't change that.