我在调试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);
有没有人有任何想法或有用的提示?
答案 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的事务不是隐式的。或者,确保嵌套事务也是隐式的。