When using the third-party framework GPUImage, the console in the project prints a warning:

Main Thread Checker: UI API called on a background thread: -[UIView bounds] PID: 2791, TID: 521508, Thread name: (none), Queue name: com.sunsetlakesoftware.GPUImage.openGLESContextQueue
Copy the code

The reason for this is clear: UI elements are accessed in child threads.

First find out where the code is accessing the UI element in the child thread, CGSize currentViewSize = self.bounds.size; currentViewSize = self.bounds.size;

GPUImageView () : GPUImageView () : GPUImageView () : GPUImageView ();

- (void)recalculateViewGeometry
{
    NSLog(@"Is main thread: %@", [NSThread isMainThread] ? @"YES" : @"NO");
    
    if ([NSThread isMainThread] == NO) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self my_recalculateViewGeometryWithSize:self.bounds.size];
        });
    } else { 
        [self my_recalculateViewGeometryWithSize:self.bounds.size];
    }
}

- (void)my_recalculateViewGeometryWithSize:(CGSize)size
{
    runSynchronouslyOnVideoProcessingQueue(^{
            CGFloat heightScaling, widthScaling;
            
            CGSize currentViewSize = size;
            
            //    CGFloat imageAspectRatio = inputImageSize.width / inputImageSize.height;
            //    CGFloat viewAspectRatio = currentViewSize.width / currentViewSize.height;
            
            CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, self.bounds);
            
            switch(_fillMode)
            {
                caseKGPUImageFillModeStretch: {widthScaling = 1.0; HeightScaling = 1.0; };break;
                case kGPUImageFillModePreserveAspectRatio:
                {
                    widthScaling = insetRect.size.width / currentViewSize.width;
                    heightScaling = insetRect.size.height / currentViewSize.height;
                }; break;
                case kGPUImageFillModePreserveAspectRatioAndFill:
                {
                    //            CGFloat widthHolder = insetRect.size.width / currentViewSize.width;
                    widthScaling = currentViewSize.height / insetRect.size.height;
                    heightScaling = currentViewSize.width / insetRect.size.width;
                }; break;
            }
            
            imageVertices[0] = -widthScaling;
            imageVertices[1] = -heightScaling;
            imageVertices[2] = widthScaling;
            imageVertices[3] = -heightScaling;
            imageVertices[4] = -widthScaling;
            imageVertices[5] = heightScaling;
            imageVertices[6] = widthScaling;
            imageVertices[7] = heightScaling;
        });
        
    //    static const GLfloatImageVertices [] = {/ f / 1.0, 1.0, f/f / 1.0, 1.0, f/f / 1.0, 1.0, f/f / 1.0, 1.0, f / /}; }Copy the code

Some students may worry that if it is the main thread, the subsequent operations will be carried out in the main thread, which is different from the original code execution process of GPUImage. This worry is superfluous, we can see runSynchronouslyOnVideoProcessingQueue () the function of the specific implementation, in has carried on the judgment can be found in this function, if the current queue is videoProcessingQueue, Then execute the code block directly, if not call dispatch_sync(videoProcessingQueue, block); Throw it inside the videoProcessingQueue to execute the block. Below is a simplified runSynchronouslyOnVideoProcessingQueue () function implementation code.

void runSynchronouslyOnVideoProcessingQueue(void (^block)(void))
{
    dispatch_queue_t videoProcessingQueue = [GPUImageContext sharedContextQueue];

    if (dispatch_get_current_queue() == videoProcessingQueue) {
        block();
    } else{ dispatch_sync(videoProcessingQueue, block); }}Copy the code