Objective-C 撤消管理器问题
我正在阅读一本关于 Objective-c 的书并了解撤消管理器。这个概念看起来很简单,但提供的示例似乎过于复杂。基本上,我有一个连接到 NSArrayController 的表视图,我可以向数组添加或删除人员,并且可以编辑他们的姓名和内容。因为该示例使用 NSArrayController 和绑定,所以添加和删除是自动的,并且所有编辑都是自动的。
要使用撤消管理器,据我了解,我需要实现自己的方法来添加/删除/编辑。
我实现的这些方法是为了执行添加和删除操作,并由于键值编码而自动调用:
- (void)removeObjectFromEmployeesAtIndex:(int)index;
- (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index;
然后为了进行编辑,我必须将类注册为观察者并观察更改以进行编辑:
- (void)changeKeyPath:(NSString *)keyPath
ofObject:(id)obj
toValue:(id)newValue
这是我的问题:
为什么我有必要做这么多吗?我的理解是,使用 NSArrayController 和绑定应该使添加/删除/编辑项目等事情变得更容易、更自动化。但是,如果我必须手动实现所有这些方法只是为了添加撤消支持,那么为什么要使用 NSArrayController 或绑定呢?
幕后发生了什么?在 Interface Builder 中,添加按钮连接到 NSArrayController 上的添加方法。那么我的 insertObject 方法是如何被调用的呢?我知道这是通过键值编码实现的,但是是什么让 NSArrayController 的 add 方法被重写,因为我的文档实现了这个方法?
解是不对称的。我使用一个概念来处理撤消添加/删除,并使用另一个概念来处理撤消编辑。难道我不能只观察数组的变化吗?我认为这会使observeValueForKeyPath 方法变得复杂,但这更有意义吗?
I'm reading a book on Objective-c and learning about the undo manager. The concept seems very simple but the provided example seems overly complex. Basically, I have a table view connected to an NSArrayController and I add or remove people to an array and I can edit their names and stuff. Because the example uses NSArrayController and bindings, add and remove are automatic and all of the editing is automatic.
To use the undo manager, from what I understand, I need to implement my own methods to add/remove/edit.
These methods I've implemented to do the adding and removing and get called automatically due to key value coding:
- (void)removeObjectFromEmployeesAtIndex:(int)index;
- (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index;
Then for editing, I had to register the class as an observer and observe changes to edit:
- (void)changeKeyPath:(NSString *)keyPath
ofObject:(id)obj
toValue:(id)newValue
Here are my questions:
Why do I have to do so much? My understanding was that using the NSArrayController and bindings was supposed to make things like adding/removing/editing items easier and more automatic. But if I have to implement all of these methods manually anyway just to add undo support, why use NSArrayController or bindings at all?
What's going on behind the scenes? In Interface Builder, the add button is connected to the add method on the NSArrayController. How then does my insertObject method get called? I know it's through key value coding but what makes the NSArrayController's add method get overridden just b/c my document implements this method?
The solution is asymmetric. I use one concept to handle undoing add/remove and another concept to handle undoing edits. Couldn't I also just observe changes to the array? I suppose it would complicate the observeValueForKeyPath method, but would that make more sense?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
1)接近,但不完全是。如果您认为应用程序代码分为三个总体区域:模型、视图和控制器(如此处记录),然后 Cocoa/XCode 环境为您提供了一种“无代码”方式来处理每个基础知识:IB 用于视图,Core Data 用于模型和控制器的绑定/对象控制器。
撤消管理主要是模型的问题,而不是视图或控制器的问题。因此,管理这些东西并不是真正的绑定或对象控制器的工作。看来您的问题是您使用数组作为数据对象,它们太轻量级,无法处理这些东西。如果您想要撤消支持,您将需要使用核心数据来处理模型并免费为您提供这些东西,或者手动滚动您自己的模型对象(可能包含数组)处理这个逻辑。
FWIW,一旦完成此操作,绑定将间接使您的生活变得更加轻松,因为当撤消命令将数据恢复到之前的状态时,视图将自动反映更改。
另外,NSArrayController 的名称有点误导——它不是用来“控制数组”的。它实际上用于控制与其他数据对象具有多对多关系的数据对象。这让我想到...
2) KVC 允许您将一个对象与其他对象之间的一对多关系视为数组或集合,而不管该关系的实际实现方式如何。它通过要求您实现方法 fitting 来实现这一点命名约定,其中与数组的原始方法非常接近集。当您调用
mutableArrayValueForKey:
或mutableSetValueForKey:
时,符合 KVC 的对象将返回代理数组或设置,这会将这些方法公开为数组。粗略地说,这就是 NSArrayController 知道要调用什么的方式 --- KVC 在数组的原始对象和从键生成其鬃毛的一些方法之间进行映射。由于您不想使用数组作为数据对象,因此能够将任何一对多关系视为普通集合通常非常有用。3)我认为这与您在错误的位置处理撤消有关。实现符合 KVC 的方法获取/设置数据对象中的属性,让它们在设置数据的同时更新 undoManger。您需要一种特殊的方法让撤消管理器恢复更改,因为您不希望撤消被记录为可撤消。或者你可以只使用 Core Data 并免费获得所有这些东西......
1) Nearly, but not quite. If you think of your application code being divided into three overall areas: Model, View and Controller (as documented here) then the Cocoa/XCode environment provides you with a 'code-free' way of handling the basics of each: IB for the view, Core Data for the model, and Bindings / Object Controllers for the controller.
Undo management is primarily a concern of the model, not the view or controller. So it's not really Bindings or the Object controller's job to manage this stuff. It looks like your problem is that you're using arrays as your data objects, which are too lightweight to handle this stuff. If you want undo support, you'll want to use core data to handle the model and give you this stuff for free, or hand-roll your own model objects, (which will probably contain arrays) which handle this logic.
FWIW, once you've done this, bindings will indirectly make your life much easier, as when an undo command reverts your data to its previous state, the view will automatically reflect the changes.
Also, NSArrayController's name is slightly misleading -- it isn't there to 'control arrays'. It's really for controlling data objects which have to-many relationships to other data objects. Which brings me on to...
2) KVC allows you to treat a to-many relationship between an object and other objects as an array or set, regardless of how the relationship is actually implemented. It does so by requiring you to implement methods fitting a naming convention, which very closely match the primitive methods of arrays and sets. KVC-compliant objects will return a proxy array or set when you call
mutableArrayValueForKey:
ormutableSetValueForKey:
, which exposes those methods as an array. Roughly, that's how NSArrayController knows what to call --- KVC maps between the primitive objects of an array and some methods whose manes it generates from the key. Since you don't want to use arrays as your data objects, it's generally very useful to be able to treat any to-many relationship as if it were just an ordinary collection.3) I think this is related to you handling undo in the wrong place. Implement KVC-compliant methods to get/set properties in your data objects, have them update the undoManger at the same time as setting the data. You'll need a special method for the undomanager to revert changes, as you don't want undos to be recorded as undoable. Or you could just use Core Data and get all this stuff for free...