Here is my code:
for (NSString *framePath in self.inputFramePaths) {
if ([weakOperation isCancelled]){
break;
}
self.currentFrame = [UIImage imageWithContentsOfFile:framePath];
CGImageDestinationAddImage(destination, self.currentFrame.CGImage, (__bridge CFDictionaryRef)frameProperties);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if ([self.delegate respondsToSelector:@selector(didFinishWritingOneFrameWithSender:)]){
[self.delegate didFinishWritingOneFrameWithSender:self];
}
}];
self.currentFrameIndex++;
}
I'm writing image frames into a file, and when each frame is written, I want to notify the UI to update a progress bar and display the image just being written. The problem is the worker queue is way faster than the ui main queue. The result is that the the ui queue delayed in receiving updates. The self.currentFrameIndex is incremented by 1 each time in the worker queue, and in the ui queue it's delayed like this:
Worker queue: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
UI main queue: 0, 2, 4, 5, 6, 7, 9, 9, 9, 9
The delay will be enlarged if I have larger frame numbers. I guess there is way to ensure the worker queue to wait for the UI queue, and guarantee the execution order. But since I care more about the processing speed, I just want to see the progress of the processing. Is there a way to skip the late events, and keep up with the processing? I want something like this if I print the currentFrameIndex:
Worker queue: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
UI main queue: 0, 2, 4, 5, 6, 7, 9
where the late events are canceled. I guess I could do some ad hoc experiments and skip every x updates, but is there a mechanism in the NSOperationQueue framework for this? I tried to put
[[NSOperationQueue mainQueue] cancelAllOperations];
outside of the loop at the end, no help...
Edit:
A very simple solution based on Amin's answer:
if (!self.isUiOperationHandled){
self.uiOperationHandled = YES;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if ([self.delegate respondsToSelector:@selector(didFinishWritingOneFrameWithSender:)]){
[self.delegate didFinishWritingOneFrameWithSender:self];
}
self.uiOperationHandled = NO;
}];
}
Well, queue means, that they are queued. ;-)
Simply set a flag, when the counter changed. Only send an update notification, if the flag is not set and at the actual value of counter. Clear the flag at the end of the delegate.
Maybe you want to send an extra message, when the loop is done.