核心动画警告:“未提交的 CATransaction”

Posted

技术标签:

【中文标题】核心动画警告:“未提交的 CATransaction”【英文标题】:Core Animation Warning: "uncommitted CATransaction" 【发布时间】:2013-01-02 10:41:47 【问题描述】:

我收到以下仅使用设备的警告:

CoreAnimation: warning, deleted thread with uncommitted CATransaction; created by:
0   QuartzCore                          0x3763c65d <redacted> + 220
1   QuartzCore                          0x3763c541 <redacted> + 224
2   QuartzCore                          0x3763fe2f <redacted> + 30
3   QuartzCore                          0x3763b9bf <redacted> + 318
4   QuartzCore                          0x3763b87b <redacted> + 50
5   QuartzCore                          0x3763b80b <redacted> + 538
6   MyApp                              0x000df597 -[CommonClass orangeGradient:] + 382
7   MyApp                              0x000f70e1 -[HomeViewController updateStatusBar] + 1700
8   MyApp                              0x000f61bd -[HomeViewController statusRecieved] + 224
9   MyApp                              0x000cd323 -[CommonClass statusReceivedFromServer] + 142
10  MyApp                              0x000d833d -[CommonClass accountStatus] + 7416
11  Foundation                          0x35a3767d <redacted> + 972
12  libsystem_c.dylib                   0x35c9a311 <redacted> + 308
13  libsystem_c.dylib                   0x35c9a1d8 thread_start + 8

我在栈顶的方法如下:

- (void)orangeGradient: (UILabel *)fillLabel 
@synchronized([CommonClass class]) 
CAGradientLayer * gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = fillLabel.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:(id)[UIColorFromRGB(0xfbb250) CGColor],(id)[UIColorFromRGB(0xf47c2a) CGColor], nil];
[fillLabel.layer addSublayer:gradientLayer];


知道为什么会出现这种情况,以及如何解决这个问题吗?

【问题讨论】:

你是在UIVIewAnimation还是NSOperation下调用orangeGradient? 直接从其他类调用方法...是NSOperation吗? 如果你在线程上使用 performSelector 那么它就是 NSOperation。基本上这个问题发生在 NSOperation 在 CoreAnimation 执行完成之前完成。这两个类之间一定存在某种关系,您需要弄清楚代码中的某个地方。 【参考方案1】:

看起来orangeGradient: 是从后台线程调用的。 Core Animation 将所有更改分组到 CATransactions 中。通常这是在运行循环中自动完成的。在后台线程上(通常)没有运行循环,因此您必须自己创建事务:

- (void)orangeGradient: (UILabel *)fillLabel 
    @synchronized([CommonClass class]) 
        [CATransaction begin];
        CAGradientLayer * gradientLayer = [CAGradientLayer layer];
        gradientLayer.frame = fillLabel.bounds;
        gradientLayer.colors = [NSArray arrayWithObjects:(id)[UIColorFromRGB(0xfbb250) CGColor],(id)[UIColorFromRGB(0xf47c2a) CGColor], nil];
        [fillLabel.layer addSublayer:gradientLayer];
        [CATransaction commit];
    

还有另一个问题:UIKit 不是线程安全的。您不能在后台线程上的 UILabel 上调用 bounds

【讨论】:

或者我应该使用performSelectorInMainThread: 调用这个方法吗? @NikitaP 是的,如果你使用 UILabel,你无论如何都会绑定到主线程。所以你也可以摆脱@synchronized @NikolaiRuhe 这是有道理的。为此+1,但她已经在主线程中调用了这个函数,所以从后台线程更新标签不是问题,但我想明确放置 CATTransaction 应该可以解决这个问题。【参考方案2】:

检查代码中是否有未提交 CATransaction。您将需要按照以下方式执行此操作;

[CATransaction begin];
[CATransaction setDisableActions:YES];
[commonClassObject orangeGradient:lblFill];
[CATransaction commit];

[编辑]

基本上,当 NSOperation 在 CoreAnimation 执行完成之前完成时,就会发生此问题。这两个类之间一定存在某种关系,您需要在代码中的某个地方弄清楚这一点。

【讨论】:

警告信息清楚地表明问题是未提交的 CATransaction。请从您调用此方法的位置发布您的代码。 这只是一个类似的调用: UILabel *lblFill = [[UILabel alloc]initWithFrame:CGRectMake (0,0,100,30)]; [commonClassObject orangeGradient:lblFill];【参考方案3】:

我只是补充一点,我在后台线程中遇到了与 initWithFrame 相同的问题。

似乎从ios 7及以上开始,对UIKit的一些调用必须在主线程下进行,不能从后台线程调用。

另请注意,在多次发出此类警告后,我的应用完全停止响应。所以最好不要忽视这样的警告。

【讨论】:

以上是关于核心动画警告:“未提交的 CATransaction”的主要内容,如果未能解决你的问题,请参考以下文章

嵌套推送动画可能导致导航栏损坏多次警告

《Motion Design for iOS》(二十七)

ios开发核心动画七:核心动画与UIView动画的区别

Android:此警告消息指的是啥? - (网络核心)

iOS_40_核心动画

核心动画与UIView