【问题标题】:KVO-related EXC_BAD_ACCESS exception on position property of CALayerCALayer 位置属性上与 KVO 相关的 EXC_BAD_ACCESS 异常
【发布时间】:2011-02-02 09:11:00
【问题描述】:

我在调试 10.6.6 上似乎与 KVO 相关的 EXC_BAD_ACCESS 异常时遇到了一些问题。

我在 CALayer 子类的 position 属性上设置了一个观察者。此特定层是自定义 CALayer 滚动层的内容层。基本上,当用户拖动内容层时,我希望在层的位置更改时发生一些 KVO 通知,以便我可以更新一些自定义 CALayer 滚动条。

以上都可以正常工作。

现在,我在 iOS 中添加了一个橡皮筋效果,这样当用户滚动超过内容区域的限制时,会遇到一些阻力,当用户放开鼠标时,内容层在 x 和 y 维度上快速回到极限位置。垂直回弹就像一个魅力。然而,由于某种奇怪的原因,任何水平的回弹都会导致上述异常发生。

我不明白为什么完全相同的代码路径(垂直回弹与水平回弹)会导致这两种情况的行为不同?这是堆栈跟踪:

CALayerTransactionFlagsLocation_ 中的 0x7fff810bbc2b_
CALayerMark 中的 1 0x7fff810bbe00
propertyDidChange 中的 2 0x7fff810bd394
3 0x7fff810bcbff in endChange
4 0x7fff810bc9f3 in -[CALayer setPosition:]
5 0x100038578 in -[MRContextualScrollLayer scrollDidEnd] at MRContextualScrollLayer.m:280...

scrollDidEnd 是当用户放开鼠标时调用的方法,并执行回弹计算以确定如何重新定位内容层以获得回弹效果。

我尝试通过在 Xcode 中的可执行文件的参数中设置环境变量来打开 NSZombieEnabled,但它没有效果,即没有记录其他信息。这使我相信问题不是内存过度释放问题,即正在访问不应该访问的对象。

scrollDidEnd 方法中导致发布 KVO 通知(然后导致崩溃)的最后一行很简单:

    _contentLayer.position = CGPointMake(_contentLayer.position.x + snapBackOffset.x,
                                         _contentLayer.position.y + snapBackOffset.y);  

有没有人有任何想法或有用的提示?

【问题讨论】:

    标签: objective-c cocoa position calayer key-value-observing


    【解决方案1】:

    正确的环境变量不是NSEnableZombies,而是NSZombieEnabled。这就是为什么设置前者没有任何作用。

    不过,Instruments 的 Zombies 乐器更有用。您可以直接从“zombie messaged”消息(在时间轴中显示为标志)开始调查消息和窗口下半部分的僵尸。

    【讨论】:

    • 抱歉,这是我的错字。在 Xcode 中,我使用了正确的 NSZombieEnabled 环境变量。我将编辑我的原始帖子以纠正错字。但感谢仪器提示。
    【解决方案2】:

    发现!

    在 -dealloc 方法中设置断点并单步执行,我在 Xcode 中看到

    #3 0x7fff810bf352 in CA::Transaction::commit

    在崩溃前收到消息。这是有道理的,因为我正在使用模式在滚动更新代码中禁用和重新启用 CA 动画:

      // Disable animation temporarily.
      [CATransaction flush];
      [CATransaction begin];
      [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
    
      //
      // Update position of CA scrollers.
      //
    
      // Re-enable animation.
      [CATransaction commit];
    

    如果我删除这个 CATransaction 动画禁用逻辑,一切正常。

    在与 KVO 相关的隐式 CALayer 事务的上下文中,似乎不支持显式事务(例如上面的包装器模式),即使文档说支持嵌套事务也是如此。此处添加的 KVO 元素是导致问题的原因。

    来自 CATransaction 文档:

    CATransaction 是核心动画 批量处理机制 层树操作成原子 更新渲染树。每一个 必须对层树进行修改 交易的一部分。嵌套 支持交易。

    Core Animation 支持两种类型 交易:隐式交易 和显式交易。隐式 交易是自动创建的 当层树被一个 没有活动事务的线程 并在何时自动提交 线程的运行循环下一次迭代。 显式事务发生时 应用程序发送 CATransaction 类一个开始消息 在修改层树之前,以及 之后提交消息。

    简而言之,如果您想让显式嵌套事务在 KVO 上下文中正确运行,请确保启动 KVO 的事务不是隐式的。或者,确保嵌套事务也是隐式的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-08
      • 1970-01-01
      • 1970-01-01
      • 2016-08-02
      • 1970-01-01
      相关资源
      最近更新 更多