CALayer的position属性上与KVO相关的EXC_BAD_ACCESS异常

时间:2011-02-02 09:11:01

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

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

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

以上一切正常。

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

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

0 0x7fff810bbc2b在CALayerTransactionFlagsLocation _
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);  

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

2 个答案:

答案 0 :(得分:0)

正确的环境变量不是NSEnableZombies,而是NSZombieEnabled。这就是设置前者没有做任何事情的原因。

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

答案 1 :(得分:0)

发现!

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

  

#3 0x7fff810bf352在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是核心动画   批处理多个机制   层树操作成原子   更新渲染树。一切   必须修改层树   交易的一部分。嵌套   支持交易。

     

核心动画支持两种类型   交易:隐含交易   和显式交易。含蓄   交易是自动创建的   当层树被a修改时   没有活动事务的线程   并在以下时自动提交   线程的run-loop接下来迭代。   当显式事务发生时   应用程序发送   CATransaction类是一个开始消息   在修改图层树之前,和   之后提交消息。

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