问题
I'm using the GPUImage framework and I've noticed that the compiler automatically skips everything that is within the brackets of the setColorAverageProcessingFinishedBlock. It completely skips over these contents and continues on, executing everything else in the code. Once everything else has been executed, it comes back to the content within the brackets. Obviously, this has unintended side effects.
NSMutableArray *redValues = [NSMutableArray array];
NSMutableArray *arrayOne = [NSMutableArray array];
NSUInteger arrayOneLength = [arrayOne count];
__block int counter = 0;
int amount = 1;
float totalOne, diffForAverage;
NSInteger j;
GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionBack];
videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
GPUImageAverageColor *averageColor = [[GPUImageAverageColor alloc] init];
[averageColor setColorAverageProcessingFinishedBlock:^(CGFloat redComponent, CGFloat greenComponent, CGFloat blueComponent, CGFloat alphaComponent, CMTime frameTime)
{ // the compiler runs until here, then skips everything within these brackets
NSLog(@"%f", redComponent);
[redValues addObject:@(redComponent * 255)];
}]; // after the brackets close, it executes everything that is below this
// once everything below this has been executed, it goes back to the brackets and executes
// everything between them
[videoCamera addTarget:averageColor];
[videoCamera startCameraCapture];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 27 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[videoCamera stopCameraCapture];
});
totalOne = [redValues[24] floatValue];
float average = totalOne / amount;
NSUInteger redValuesLength = [redValues count];
for (j = (counter + 24); j < (redValuesLength - 24); j++)
{
diffForAverage = average - [redValues[j + 1] floatValue];
if (diffForAverage > -1 && diffForAverage < 1)
{
totalOne += [redValues[j + 1] floatValue];
amount++;
[arrayOne addObject:[NSNumber numberWithInt:(j - 24)]];
counter++;
}
}
How can I solve this problem?
回答1:
There are two issues with the above code: a memory management one, and a misunderstanding of how blocks work.
First, you're creating a GPUImageVideoCamera instance within a method, but not retaining it as an instance variable. I'm going to assume this is code using automatic reference counting, and if that's true, this camera instance will be deallocated the instant your method is finished. At best, you'll capture maybe one frame from the camera before this is deallocated. At worst, this will crash as the camera and the entire filter chain attached to it are deallocated mid-operation.
Make an instance variable on your containing class and assign your GPUImageVideoCamera instance to it to have it last long enough to be useful.
The second issue with the above is a misunderstanding about how and when blocks will execute. Blocks are merely sections of code you can pass around, and they don't necessarily execute in serial with the rest of the code around them.
In this case, the block you're providing is a callback that will be triggered after every frame of video is processed through the average color operation. This processing takes place asynchronously on a background queue, and you have to design your code to acknowledge this.
If you want X values to be built up, have each measurement be added to an array inside that block, and then within the block check for X values to be reached. At that point, average and do whatever with them. Basically, add a check within the block and move the code you have after it into the block to be run whenever the count is greater than X. You may wish to stop camera capture at that point, if that's all you need.
回答2:
The code you post is working exactly as it is supposed to work. The color average processing takes a while so it is done on a background thread so the main thread isn't stalled. After the processing is done, then the block is called.
Any code that shouldn't be executed until after the processing is done needs to go inside the block.
来源:https://stackoverflow.com/questions/41666622/objective-c-block-doesnt-skips-code-and-then-later-executes-it