Forcing Managed Object to be dirty - objective-c

Is there a way to force a managed object into the dirty state? I have a managed object that has a relationship to a parent managed object. If I change a property on the child managed object, I was curious if there is a way to put the parent managed object into a dirty state.

On Mac, you should use NSPersistentDocument for most cases where this would be useful.
On iOS 5+, you should use UIDocument.
If these aren't possible, then you can either have the parent observe changes in its children, or have children set a changed flag on their parent. In either case, you can modify some "last changed" property to cause yourself to become dirty.
You can also create a method like -hasChangedChildren that would walk the children tree and return YES if any are dirty. This has the advantage of not actually modifying the object, so you don't impact any Core Data optimizations. The docs do not forbid modifying hasChanges to behave this way, but I would personally be careful doing so.
But if at all possible, you should use the document classes, since this is what they're for.
You may also be interested in Core Data Questions--Relationships, UUIDs, and Dirty States.

Related

Is it bad to use a watch in a child component?

In my project, I need to know the changes in the child components in real time from the parent component.
So I'm going to use watch in a child component to emit event to the parent component whenever the data in the child component changes.
Is this a bad way? I'm afraid there's an unnecessary overload in this flow.
If you have a better way, please recommend it.
There's nothing wrong with this approach. Vue is very efficient in the way it detects changes, and there shouldn't be an unnecessary overload, unless you watch more than you need to. You shouldn't notice any performance issues unless you have a huge object graph (eg thousands of objects being watched).
Make sure you only watch the properties that require change detection, and only use deep:true if you really need to.

Have NHibernate ignore not set properties?

I have a huge object, it has a lot of lazy loadable properties.
I want to enable a quick edit of a very small subset of its property.
How can I, when I just have a few values, tell NHibernate: don't touch anything else?
Because now, when I save, everything not set gets lost.
Have you tried dynamic-update option on your class mapping?
<class name="SomeEntity" dynamic-update="true">
But check if the flush does not cause the unloaded lazy properties to get loaded first, just in case.
In your question, you state you lose other properties. I have never witnessed such a behavior. Are you attaching (using ISession.Update or ISession.Merge) a detached entity in your current code?
What I am suggesting will not work in such a case. It should instead work with an entity loaded from the current ISession, touched on some properties then saved to db only using ISession.Flush (or preferably, ITransaction.Commit, since it is not a good practice to work without transactions).

How to observe a Core Data relationship before it gets actually changed?

I am trying to find a way of observing a Core Data relationship (more specifically the removed items of an unordered relationship) before it gets actually changed. You can imagine it as a "will change" notification known from other Cocoa APIs.
The reason is that I want to update the UI according to these changes and I need a parameter which isn't stored in the managed objects but in an other data structure (in my case it's the index from a NSArrayController). I can retrieve the parameter only if the items weren't removed from the relationship yet.
The only way of getting such "will change" notifications I could find was to override the KVO method -willChangeValueForKey:withSetMutation:usingObjects: in the custom NSManagedObject subclass and forward this information. The problem is the documentation says: "You must not override this method." and this makes me want to find a better solution.
Is the "will change" approach right in this case?
If so, how could I achieve it? If not, how should I solve the mentioned problem in another way?
You can just override the relationship’s setter method instead.

Objective-C undo manager questions

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?
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: or mutableSetValueForKey:, 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...

Can a collection in NHibernate be mapped as read-only?

I have a mapping defined where a parent object has a collection of child objects. In my design, I'd like to be able to delete the child objects without having to remove them from the collection on the parent object and re-saving the parent object. However, when I try this, I get the "deleted object would be re-created on save" error. Is there a way to prevent this such that I could simply delete the child object and not worry about removing it from the parent's collection too? That feels like doing double the work. Ideally I'd like to treat the parent's collection as read-only from NHibernate's perspective.
It'd help if you post your mapping files, but it sounds like you need to add Inverse=true to the collection mapping. This means that the child object is responsible for handling any save or updates, not the parent.
However, in the database it's all modelled the same. The child should have a column for the parent row's ID. NHibernate will create different SQL based on the Inverse property though. I'd like to give more detail, but I'm learning NHibernate myself as well.
I believe the only thing you need to do is just set the collection of child objects in the parent's mapping file to be cascade="none".
Of course that will also prevent saving child objects by assigning them to the parent's collection and updating the parent. If that is OK then you got your solution.