Reputation: 68596
I am quite new to iOS development and I'm facing a multithreading issue.
I'm using KTPhotobrowser with SDWebImage to create a photo and video gallery. I have to load some external data on each picture, and I don't want to affect the smoothness of the gallery's scroll view.
So, I'm trying to do that using NSOperation
and NSOperationQueue
, but I'm not sure I'm doing right.
What I want is to stop the loading process if the user doesn't stay on the picture and keep scrolling.
My current code:
//setCurrentIndex is called when the scrollView is scrolled
- (void)setCurrentIndex:(NSInteger)newIndex {
[loadingQueue_cancelAllOperations];
currentIndex_ = newIndex;
[self loadPhoto:currentIndex_];
NSInvocationOperation *InvocationOp = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadInfosAtIndex:) object:newIndex];
[loadingQueue_ addOperation:InvocationOp];
[InvocationOp release];
[selfloadPhoto:currentIndex_ + 1];
[selfloadPhoto:currentIndex_ - 1];
[selfunloadPhoto:currentIndex_ + 2];
[selfunloadPhoto:currentIndex_ - 2];
}
-(void) loadInfosAtIndex:(NSInteger)index {
if (index < 0 || index >= photoCount_) {
return;
}
KTPhotoView* photoView = [photoViews_ objectAtIndex:index];
if([photoView infosAlreadyLoaded]){
NSLog(@"%d Already Loaded", index);
return;
}
//Get the extra information by calling a web service
photoView.infosAlreadyLoaded = YES;
}
I don't think this is the proper way to do this... has anyone got any advice?
Upvotes: 2
Views: 369
Reputation: 18697
Instead of relying on a scheduling-based cancel, which can leave you in an uncertain state, have a cancelling instance variable that has atomic access (either via an atomic property or a BOOL ivar with a mutex).
Then, instead of [loadingQueue_cancelAllOperations], you simply set the canceling flag to YES and check it in loadInfosAtIndex periodically. This is essentially polling for the cancel, and if the code is involved, it can be a pain. But it has the advantage of letting you be able to handle the cancel gracefully by reading the flag. As a part of handling, you can set an isRunning flag (also needs to be atomic/mutexed) to NO and exit the thread by returning.
In the main thread, after setting the cancelling flag to YES, you can wait till the isRunning flag is NO before opening up a new thread.
Upvotes: 3
Reputation: 1494
[loadingQueue_ cancelAllOperations], simply doesn't cancel the operations immediately, it only cancels the operations in the queue that has not yet started executing.
If the operation in the queue has already started then it is removed only after the operation is completed. More about cancelAllOperations
I think you might want to use GCD async for that where you might remove the currently executing block.
Upvotes: -1