I'm trying to understand this piece of code.I just noticed the link you posted before and see they are suggesting the same thing, so I'll do my best to try and translate so you can understand what you need to do. Let me know if I'm unclear since I'm making metaphoric pictures here.
In your case, you are displaying the value of hairColor which is a property on the relationship of looks. When you are displaying the Woman entity in a row, you are essentially superimposing hairColor as if it were a property directly on the Woman entity. We can visualize this superimposition through a computed property, which doesn't have data but gathers it elsewhere via its getter, and in this case is something like:
Code:var hairColor: UIColor { get { self.looks.hairColor } }
Now, the issue comes from changing the value of hairColor. When updated, the entity Looks is actually the only object that changed, and because that object isn't observed by FRC there are no updates even though Woman superimposes that variable. The FRC doesn't have a way to be told that any random object change relates to Woman since Woman is the object extending the graph outside of the FRCs knowledge.
So, our goal is to let the graph know that changing the property hairColor on Looks actually affects its children. This can be done two ways depending on how extensive relationships affect their children.
The first and easiest, and the method I would suggest for you, is to write a custom setter on the Looks entity that the property is changing on, a la:
(Take this as reference, I wrote it on my phone so I'm pretty sure it won't compile :S)Code:var hairColor: UIColor? { set { self.willChangeValueForKey("rawHairColor") self.setPrimitiveValue(ConvertColorForDBStore(newValue), forKey: "rawHairColor") self.didChangeValueForKey("rawHairColor") self.willChangeValueForKey("woman") //Notify the graph that the woman relationship will change self.didChangeValueForKey("woman") //It didn't, BUT it triggers KVO as if it had } get { self.willAccessValueForKey("rawHairColor") let color = ConvertDBStoreToColor(self.primitiveValueForKey("rawHairColor")) self.didAccessValueForKey("rawHairColor") return color } }
There's a few things to take into consideration, but I believe it will get my point across. First, that I don't override or use property observers - this is because you cannot override NSManaged properties and it makes the API for normalizing values before storing into the database extremely clean. The magic in this snippet is the KVO that fires on the (one-to-one assumed) relationship - it tells the graph that the relationship property needs to be reevaluated.
In the grand scheme of things, that object on the other side of the Look relationship is Woman and it will be marked dirty and therefore be registered by the FRC as needing an update.
I'll hint at the second method but won't go into detail: Instead of having the ManagedObject subclass mark its relationship as dirty, you can have an object subscribe to Notification Center to listen for NSManagedObjectContextObjectsDidChangeNotification and manually move though the graph to mark the entities which relate to the changed entity as dirty. This makes more sense when dealing with deeper relationship nests and especially when working with self-referencing relationships.
1 However you are referring to Woman as the child. Woman is the parent though. Woman has a relationship looks. On that looks you can find the property haircolor. So Woman is the parent.
2 I get the impression you are suggesting to put an extra property on Woman named hairColor. This property would be computed and get its value out of self.looks.hairColor
3 The second bunch of code: is this on the entity Looks or on the entity Woman?
4 So the goal seems to me that a change in hairColor affects its parent?
[doublepost=1452958351][/doublepost]
I think I know you mean. I put an extra stored variable property on my editVC. As it is on the Controller I'm not changing the model hence respecting MVC. This extra variable property was called myHairColor. It is a computed property as you can notice in the following code. The code does change the value of hairColor in CoreData but does NOT trigger the frc update. What's wrong with it?Breaking MVC? How?
MVC is more about separation of responsibilities and in my example, your model is only responsible for telling itself that additional pieces of it are dirty - this already happens when setters and getters are managed by Core Data (via willChangeValue and didChangeValue) but is scoped to the single property. There's a thread where I recently talk about the dynamic keyword in Objective-C, and Core Data uses this (with NSManaged) to create the setter and getter within the managed subclass instance but defined out of the superclass.
Bigger picture, this prevents scope creep of the FRC since it continues to only react to the changes on its own object set as it would if you were using Core Data's generated functions in any other case. If I were to present a solution that required you to amend the FRC to observe more properties than its initial fetch request, I'd be a little more wary about misaligning responsibilities because things begin to get sloppy very quickly as that would require redefining those relationships & dependencies outside of your model for a use case.
Ideally, you should be informing each child in the relationship of a change to a property in the parent only if the changed property affects the child. In this case, hairColor clearly affects Woman but something like hairProduct could not, so you wouldn't want the parent (Looks) to mark its child (Woman) as dirty since there is no noticeable change to the woman object. This means that you must manually be aware of and anticipate how changes affect other objects, but also means that you are not firing KVO operations willy-nilly (could result in craziness, instability, or just redundant processing).
--
As I've stated before, the second method I presented to you will need to be handled and conceived entirely by you per your design. I can't really describe more beyond this and maybe a small snippet:
Essentially, when that notification is fired, you're given a MOC and list of objects which have changed. You'll need to find which changed objects affect others, then do a little logic to ensure that any other objects that should react on that changed object are affected, and finally mark them as dirty through KVO accessing. This makes it easier to manage a relationship like:
Woman <-> Looks <-> HairColorsSince an update to HairColors (e.g., a title property from "blond" to "blonde") is acknowledged by Woman regardless of the objects in the graph that are separating the two.
Code:
var myHaircolor: String? {
set(newHairColor) {
self.looks?.hairColor?.name = newHairColor
self.willChangeValueForKey("woman")
self.didChangeValueForKey("woman")
}
get {
return self.looks?.hairColor?.name
}
}