Why updating CALayer causes increase of CPU usage (by other processes) by 60-70%?

天涯浪子 提交于 2019-12-11 18:35:44

问题


I am witing IOS app when interface is presented by many CALayers. Once I noticed that CPU is loaded by other processes (not app actually) during graphics updates. I began to disabled updating of interface parts and went to the moment when only ONE CALayer was updated (at 50-60 Hz), but all other layers (hundreds) were statically displayed too. So updating of only this ONE layer costs 60-70% of CPU load by other processes. When disable update of this only layer, CPU is not loaded.

Can anyone say what is going on here??

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

// update layer which is sublayer of self.view.layer
self.headingCircularScaleLayer.transform = CATransform3DMakeRotation(DegToRad(-newHeadingAngle_deg), 0, 0, 1);

[self.view.layer setNeedsLayout];

[CATransaction commit];

Here headingCircularScaleLayer is CALayer which contents is set to some Image

NOTE_1: (test of CPU load by adding many layers and updating them)

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

-(void) viewDidAppear:(BOOL)animated {

    [self createAndSetupLayers];

    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateLayers)];
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

    self.startTime = [[NSDate date] timeIntervalSince1970];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


-(void) createAndSetupLayers {

    NSMutableArray<CALayer*>* newLayersArray = [[NSMutableArray alloc] init];

    long numOfRows = 28;
    long numOfCols = 21;
    long numOfLayers = numOfRows * numOfCols;

    CGFloat cellWidth = self.view.bounds.size.width / numOfCols;
    CGFloat cellHeight = self.view.bounds.size.height / numOfRows;

    CGFloat layerWidth = cellWidth * 0.9;
    CGFloat layerHeight = cellHeight * 0.9;

    long currRow = 0;
    long currCol = 0;

    for (long i = 0; i < numOfLayers; i++)
    {
        currRow = i / numOfCols;
        currCol = i % numOfCols;

        CALayer* newLayer = [[CALayer alloc] init];

        newLayer.bounds = CGRectMake(0.0, 0.0, layerWidth, layerHeight);
        newLayer.anchorPoint = CGPointMake(0.5, 0.5);
        newLayer.position = CGPointMake((currCol + 0.5) * cellWidth, (currRow + 0.5) * cellHeight);
        newLayer.backgroundColor = [UIColor greenColor].CGColor;
        //newLayer.opacity = 0.5;

        //NSDictionary *newActions = @{ @"transform": [NSNull null] };
        //newLayer.actions = newActions;
        newLayer.actions = @{ @"contents": [NSNull null], @"position": [NSNull null],
                           @"frame": [NSNull null], @"opacity": [NSNull null],
                           @"bounds": [NSNull null], @"affineTransform": [NSNull null],
                           @"sublayerTransform": [NSNull null], @"transform": [NSNull null],
                           @"zPosition": [NSNull null], @"anchorPoint": [NSNull null],
                           @"cornerRadius": [NSNull null], @"sublayers": [NSNull null],
                           @"onLayout": [NSNull null], };


        CALayer* newColorLayer = [[CALayer alloc] init];
        newColorLayer.bounds = CGRectMake(0.0, 0.0, layerWidth, layerHeight);
        newColorLayer.anchorPoint = CGPointMake(0.5, 0.5);
        newColorLayer.position = CGPointMake(0.5 * layerWidth, 0.5 * layerHeight);
        newColorLayer.opacity = 0.5;
        newColorLayer.opaque = YES;
        newColorLayer.backgroundColor = [UIColor redColor].CGColor;

        //[newLayer addSublayer:newColorLayer];
        [self.view.layer addSublayer:newLayer];
        [newLayersArray addObject:newLayer];
    }

    self.layersArray = newLayersArray;
}

-(void) updateLayers {
    double currTime = [[NSDate date] timeIntervalSince1970] - self.startTime;

    double currLayerAngle = 0.5 * currTime;

    NSLog(@"%.2f  %.2f", currTime, currLayerAngle);

    //[CATransaction begin];
    //[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
    //[CATransaction setAnimationDuration:0.0];

    for (CALayer *currLayer in self.layersArray)
    {
        currLayer.transform = CATransform3DMakeRotation(currLayerAngle, 0, 0, 1);
    }

    //[CATransaction commit];
}

@end

回答1:


As said in the comments above, setting kCATransactionDisableActions will only affect the current transaction. You might have code in other places that starts implicit animations. Try explicitly setting the layer actions to null. You only need to do this once, when the layer is created. In this case you don't need to do explicit transactions.

layer.actions = @{ @"contents": [NSNull null], @"position": [NSNull null],
                   @"frame": [NSNull null], @"opacity": [NSNull null],
                   @"bounds": [NSNull null], @"affineTransform": [NSNull null],
                   @"sublayerTransform": [NSNull null], @"transform": [NSNull null],
                   @"zPosition": [NSNull null], @"anchorPoint": [NSNull null],
                   @"cornerRadius": [NSNull null], @"sublayers": [NSNull null],
                   @"onLayout": [NSNull null], };


来源:https://stackoverflow.com/questions/54590531/why-updating-calayer-causes-increase-of-cpu-usage-by-other-processes-by-60-70

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!