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?
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.