Can't do that self.user. Services does not return a mutable set. That's what that addServicesObject method is for.
Change the second line to.
NSMutableSet *userServices = self.user. Services; ... userServices addObject:service; Can't do that. Self.user.
Services does not return a mutable set. That's what that addServicesObject method is for. Change the second line to: self.
User addServicesObject:service; From Apple documentation: It is important to understand the difference between the values returned by the dot accessor and by mutableSetValueForKey:. MutableSetValueForKey: returns a mutable proxy object. If you mutate its contents, it will emit the appropriate key-value observing (KVO) change notifications for the relationship.
The dot accessor simply returns a set. If you manipulate the set as shown in this code fragment: aDepartment. Employees addObject:newEmployee; // do not do this!
Then KVO change notifications are not emitted and the inverse relationship is not updated correctly. Recall that the dot simply invokes the accessor method, so for the same reasons: aDepartment employees addObject:newEmployee; // do not do this, either!
Commented before, but also not the issue. It does work since some of the objects are restored after relaunch. Self.user.
Services does return an NSMutableSet, in fact adding the addServicesObject helper method is optional.User. Services is equivalent to user valueForKeyPath:@"user. Services".
Otherwise how come some of them get saved? – pablisco Dec 21 '11 at 11:22 Shouldn't you be using the mutable set accessor, like this: NSMutableSet *userServices = self mutableSetValueForKeyPath:@"user. Services";?
– paulbailey Dec 21 '11 at 14:45 1 Really? I wasn't aware that the dot notation returned a mutable proxy object. – paulbailey Dec 22 '11 at 9:26 5 You can lead a horse to water ... See documentation added above."It works sometimes, so obviously I'm doing it right," is not good logic.
Casting something to the wrong type will invoke undefined behavior, so it might work right because who knows why. You declare the property, so you can declare it as NSMutableSet, but the dynamic definition of the property is not returning that, so you are misleading the compiler. Or it might be returning an NSMutableSet but not one that actually modifies your persistent data.
Since it doesn't work, you might try the documented proper method? – morningstar Dec 28 '11 at 4:11 2 What I've done when I needed this is to implement a mutableServices method that returns self mutableSetValueForKeyPath:@"user. Services" and that works.
Simply casting is NOT supported at all and leads to undefined behavior. – Daniel Eggert Dec 29 '11 at 9:57.
I've the same problem, but after set up the inverse relationship, everything is OK again. I hope this helps investigating this issue.
I tried that but I still get missing relationships :( – pablisco Dec 21 '11 at 12:52.
In the end I have solved it by using a custom NSPredicate that fetches the services using one special parameter that I set on services when they are added by an user. It works although it's not ideal.
Okay, let's look at the symptoms here. You are making changes to objects within a context, but when you restart the app, some but not all of these changes are there. This can only mean that these changes are not being written to the persistent store.
Since you are seeing some of the changes, you are calling the save: method, but Core Data is not recognising all the objects as needing to be saved. This leads us to how you are performing the changes to said objects. Are you making the changes in a KVO-compliant manner?
Core Data relies on KVO to know what changes have occurred, and therefore what changes need persisting. If you change the objects in a non-KVO fashion, they will appear to be changed when you examine them, but Core Data will not know that these changes exist, and will therefore not know that it must persist them. I would amend your code as follows, providing the Service object has the inverse relationship back to the User (and that relationship is called user, and part of a 1-M): servicesToAdd setValue:self.
User forKey:@"user"; NSError *error = nil; if (!service managedObjectContext save:&error) { NSLog(@"Saving failed"); NSLog(@"Error: %@", error localizedDescription); } This relies on the fact that Core Data will take care of both ends of the relationship for you, where an inverse relationship is set up. Of course, if it's a many-to-many relationship, then the code is slightly different, but we still use the KVO-compliant methods to make the changes. ServicesToAdd setValue:self.
User forKey:@"user"; for (Service *service in servicesToAdd) { user addServicesObject:service; } NSError *error = nil; if (!service managedObjectContext save:&error) { NSLog(@"Saving failed"); NSLog(@"Error: %@", error localizedDescription); }.
It's a M-M relationship. I recognize now that I can't use the dot accessor directly to add the objects and I was also understanding that CD takes care of the reverse relationships. Also, I've tried to use the addServicesObject instead of the dot accessor with similar results.
– pablisco Dec 29 '11 at 11:17 You seem to be checking whether the object is already in the set before you add it. I think this is probably an unnecessary complexity. Just add the service to the set, and let Cocoa and Core Data determine whether it's a) already there (an NSMutableSet doesn't allow the same object to be added twice) and b) whether there's a change that needs saving to the persistent store.
Let the frameworks do the work for you where they can. – paulbailey Dec 29 '11 at 11:32 I added that as a separate fix because I was getting duplicates. But that's a different story (I think).
I know you can't have the same object but you can have two objects with the same data. And the save action was just an attempt to see if that was the problem. I wasn't saving them before.
– pablisco Dec 30 '11 at 14:25 Perhaps you could try calling hasChanges on the object after you've made your changes, to ensure that Core Data has noticed? – paulbailey Dec 30 '11 at 14:50.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.