NSArrayController Entity Attribute Mysteriously Dropped
Asked Answered
N

0

7

I have an NSArrayController bound to a Core Data entity — Channel. I have a method that updates the entity after a user changes the title of the Channel:

NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
NSString * savedTitle = [fieldEditor string];
self.mainWindowController.selectedChannel.channel_name = savedTitle;
[localContext MR_saveToPersistentStoreAndWait];

(I'm using MagicalRecord, in case that's not clear)

By all accounts, this save works — the value is reflected when the change is made, and if I immediately check the persistent store using Core Data Editor I can see the change has been saved.

The problem occurs when I change the view — the change is made in a master view, and the user can switch to a detail view. This line of code, which swaps out the master view, marks the spot where trouble occurs:

[[self.chatsViewController.view animator] removeFromSuperview];

After this line executes, the newly-saved value is gone. Requests to the entity attribute returns an empty string.

But here's the weird part. If I restart the application, the new value is still there! It comes back, and this time it's here to stay. Also, looking at the persistent store, I never see the value disappear at any point. This suggests that my array controller is getting the value taken away somehow.

I've tried refreshing the array controller after the save to "lock it in", as it were. But this appears to have no effect.

Can anyone suggest what steps I might take to track this down? I can't fathom why removing a view would cause this to happen.

Update As I noted in my comment below, I tried putting a log statement on the name attribute's setter in my entity subclass, and it yielded a log entry when I changed the name, but never after.

I've now done another experiment: looking at the Core Data record both before and after the view switch.

NSArray * channels = [Channel MR_findAll];
NSLog(@"Channel: %@", [[channels objectAtIndex:0] channel_name]);

[[self.chatsViewController.view animator] removeFromSuperview];

NSArray * channels2 = [Channel MR_findAll];
NSLog(@"Channel2: %@", [[channels2 objectAtIndex:0] channel_name]);

The result:

Channel: adfasd
Channel2:

I have to be missing something here.

North answered 19/11, 2013 at 19:34 Comment(11)
are you doing any multithreading with your managed object?Itemized
It looks like you're working with an NSTextView and grabbing the string from there, is that right? Does that update method get called via an NSTextView delegate method? Bindings? Target/action?Loaning
@PatrickGoley: I'm not multithreading here.North
@BrianWebster True. That method is from a controller acting as a delegate. The method is - (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor. Relevant?North
I guess my thought was that perhaps somehow that delegate method might be getting called again as a result of removing the text view from the window. If the text view's string at that point was empty, that could propogate the new value into the managed object's attribute. However, that wouldn't fit with the fact that it's not going all the way to the persistent store, since those things all happen in that same method. It seems like the managed object is being updated, but through some other code path that doesn't save to the store.Loaning
I just did an experiment: on my Channel entity subclass I added a setter method to log when the name changes. It fires when I change it, but doesn't fire when the value is dropped in the view transition. I'm still looking...North
Is the text field configured to update continuously, or only on end editing? Any chance you have a binding configured for the text field that you forgot about? Like in the nib?Avidity
You write your NSArrayController is "bound to a Core Data entity". Managed objects need a Managed Object Context to live in. Which Managed Object Context are you using to provide your controller with data? Looks like the one shown in your question will just be released, invalidating all Managed Objects which were fetched in it.Massimo
@BoredAstronaut The text field is configured to update the value when the user hits Return; I double-checked the NIB and there's no binding there...North
@Massimo I'm using MagicalRecord, and I treat the class method MR_defaultContext like it's a singleton method... which I take it isn't. However, a test shows the MOC is the same when called at any point in the app (using NSLog with %p). Not sure this is the issue.North
It sounds like a context problem, I had a similar issue, the data was here and then it was gone and then it was here again. In the end it turned out that I was using different context. U just need a good debug strategy, its hard to guess what is wrong. Try a dummy simple app that deals only with the problem in hand. Then build on it. It seams like a lot of work but it really is not, and success is guarantied.Croquet

© 2022 - 2024 — McMap. All rights reserved.