Search code examples
iosmultithreadingcalayer

Is it safe to change a CALayer's attributes from a background thread?


I want to do an animation that is responsive to device motion and I'd like it to remain smooth even if the UI thread is momentarily busy. The animation consists of changing a CALayer's bezier path. I've tried doing it from a secondary thread but I get occasional hangs where the main thread has a trashed stack. Is what I'm doing totally hopeless? Here's what I do in the thread:

[CATransaction lock];
[CATransaction setValue:(id)kCFBooleanTrue
                 forKey:kCATransactionDisableActions];
[CATransaction begin];
myLayer.path = [UIBezierPath bezierPathWithOvalInRect:theRect].CGPath;
myLayer.bounds = theBounds;
[CATransaction commit];

[CATransaction flush];
[CATransaction setValue:(id)kCFBooleanFalse
                 forKey:kCATransactionDisableActions];
[CATransaction unlock];

Solution

  • updating the ui from any thread except the uithread is prohibited so you will have to do the following:

    - (void) updateUI
    {
    [CATransaction lock];
    [CATransaction setValue:(id)kCFBooleanTrue
                     forKey:kCATransactionDisableActions];
    [CATransaction begin];
    myLayer.path = [UIBezierPath bezierPathWithOvalInRect:theRect].CGPath;
    myLayer.bounds = theBounds;
    [CATransaction commit];
    
    [CATransaction flush];
    [CATransaction setValue:(id)kCFBooleanFalse
                     forKey:kCATransactionDisableActions];
    [CATransaction unlock];
    }
    

    and from the other thread

    [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:YES];