【问题标题】:make NSUndoManager ignore a property of an NSManagedObject使 NSUndoManager 忽略 NSManagedObject 的属性
【发布时间】:2014-05-02 16:31:28
【问题描述】:

我的应用程序的主要功能是在绘图上排列对象。整个事情是基于Core Data,情节上的每个对象都由一个实体表示。在本例中,该实体将是“Unit”,它是 NSManagedObject 的自定义子类。

当绘图打开时,每个 Unit 都会创建一个 UnitViewController,KVO 会观察到 Unit 属性的变化,例如 .positionX、.positionY 和 .angle。 UnitViewController 检测到的触摸手势会修改 Unit 对象,并且视图会在观察到它们时通过移动自身来做出响应。这允许在没有太多额外代码的情况下轻松实现撤消和重做,当数据库更改时,单元会自行移动。

删除单元时出现问题。

Unit 的一个属性是 .viewController,它指向链接到它的 UnitViewController。这是一个瞬态属性,因为显然我不需要它持续存在;每次打开情节时,我都会重新创建它。 (UnitViewController 有一个属性 .object,它指向它的 Unit;本质上是一个逆属性。)问题是,当我撤消删除或重做创建的撤消时,Core Data 会尝试恢复 .viewController 属性,但是该 UnitViewController 对象已被释放。在我启用僵尸之前,我得到了一个 EXC_BAD_ACCESS,这给了我这个:

*** -[UnitViewController retain]: message sent to deallocated instance 0x18365780

所以我的问题是:如何让 NSUndoManager 完全忽略该属性?我尝试在修改之前关闭撤消注册,甚至覆盖 Unit+LD.m 中的 setter 方法(我在 Unit.m 上的类别,它是 NSManagedObject 子类):

- (void)setViewController:(UnitViewController *)viewController
{
    [self.managedObjectContext.undoManager disableUndoRegistration];

    [self willChangeValueForKey:@"viewController"];
    [self setPrimitiveValue:viewController forKey:@"viewController"];
    [self didChangeValueForKey:@"viewController"];

    [self.managedObjectContext.undoManager enableUndoRegistration];
}

但是,当我撤消删除时,它仍然会尝试恢复 .viewController。以前有人处理过这样的事情吗?有没有更好的方法来解决这个问题?

【问题讨论】:

  • 将托管对象引用提供给视图控制器是很奇怪的,为什么这是必要的?通常,视图控制器会保存对它正在处理的模型对象的引用,但是反向连接是非常不寻常的。
  • 这对我来说也有点奇怪,但它允许我在执行某些操作时非常快速地向视图控制器发送消息。视图控制器都相互交互很多,并且通过使用 .viewController 属性,我使它们能够非常有效地相互交谈。我还可以根据返回托管对象集的 Core Data 获取结果执行操作,而不是枚举我工作区的所有 childViewController 并检查它们是否符合某些条件。
  • 不过,缺点显然大于好处。您可以保留一个简单的集合(例如字典),其中包含指向活动对象和视图控制器的指针。这不应该比您有问题的解决方案复杂得多。
  • 不幸的是,它更复杂。我很早就开始考虑这个想法,而我正在编写的代码很快就变得昂贵了。枚举我的 PlotViewController 的 childViewController 并查看它们的 .object 属性是否与我正在寻找的托管对象匹配并不复杂,但是即使是简单的绘图,四五个嵌套枚举也开始对性能造成影响。当然,您可能完全正确,否则无法解决问题,但我认为在重写我的一半代码之前看看是否有人有解决方案不会有什么坏处!

标签: objective-c core-data uiviewcontroller key-value-observing nsundomanager


【解决方案1】:

我最终向 Apple 提交了支持票,他们立即回复了一个非常简单的答案:覆盖 Unit.m 中的设置方法 -setViewController: 并将其设为空。 (或者在 Unit+LD.m 中,在我的情况下,因为我在一个类别中执行所有自定义内容,以避免在更新我的数据模型时必须重新执行。)

- (void)setViewController:(UnitViewController *)viewController {

}

我只在代码中设置了几次属性,当我这样做时,我只使用 -setPrimitiveValue:forKey: 代替。我还有一些测试要做,以确保其他一切正常,但就目前而言,它似乎像一个魅力。撤消管理器从未尝试恢复该属性,并且我已不再出现崩溃。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    相关资源
    最近更新 更多