Reputation: 16720
In my CoreData model, I have an entity called Contact. It has an attribute called profileImage
, with the type set to Transformable.
In the Contact class (a subclass of NSManagedObject), I've changed profileImage from being a generic id to being an UploadedImage:
@property (nonatomic, retain) UploadedImage * profileImage;
The UploadedImage class has a few properties of its own.
The problem is that CoreData doesn't know when the properties on the UploadedImage object have changed. If only those properties are changed, the willSave
method is never called on the Contact object when the managed object is saved. It works as expected if I change any other property on the Contact object: it just doesn't "see" changes to anything on the UploadedImage object within the Contact object.
What's the correct way to indicate that the managed object needs to be saved? Should I manually call willChangeValueForKey:
and didChangeValueForKey:
for the key 'profileImage' on my Contact object?
Edit to clarify a couple things
NSCoding
protocol methods, I think). If I change a property on the ImageUpload object, AND change a property on the Contact object, the Contact is saved, and that changed value persists on the ImageUpload object when the Contact is loaded from CoreData again.Upvotes: 4
Views: 2038
Reputation: 365
Expanding upon Scott's solution (no copy necessary!), here is a method for Swift that works with any field:
static func markDirty<C, T>(_ obj: C, _ keyPath: ReferenceWritableKeyPath<C, T>) {
obj[keyPath: keyPath] = obj[keyPath: keyPath]
}
Used like so:
NSManagedObject.markDirty(playlist, \.rules)
Unfortunately it's not possible right now to define it as an instance method, due to limitations with generics.
Upvotes: 0
Reputation: 16946
Unless there's another way I'm not aware of, it sounds like marking the NSManagedObject
as dirty is the way to go. You can do that using a separate dirtyFlag
attribute, or by simply using the profileImage
attribute itself.
One way to automate this would be KVO. You observe all properties of UploadedImage
in the Contact
class, and then just call self.profileImage = self.profileImage
. I'm not sure if this is optimized by the compiler. If it is, you can also call willChangeValueForKey:
and didChangeValueForKey:
, which should trigger it. If Core Data noticed that the object didn't actually change, you can try to implement NSCopying
and assign a copy of the original UploadedImage
.
Upvotes: 3
Reputation: 7414
I don't believe Core Data will persist changes made to the subclass. The contract in Core data is between the parent entity and Core Data, so Core Data only responds to changes made to the properties in the entity class.
You can get around this by making that property a NSDictionary
in the Entity and in the subclass add the image object to the dictionary.
Upvotes: 0