Apple's documentation on -setPrimitiveValue:forKey:
is vague in two ways when using it to manage to-many relationships.
First they state:
If you try to set a to-many relationship to a new NSMutableSet object, it will (eventually) fail.
Eventually?! What does that even mean? Will it fail later during -[NSManagedObjectContext save:]
? When an managed object is turned into a fault and then paged back in? When? Can I write a test case to consistently recreate the failure on-demand?
Second, providing sample code to correctly handle this case, they write:
first get the existing set using
primitiveValueForKey:
(ensure the method does not returnnil
)
What should I do if/when the method does return nil? assert()
it and fail immediately because that means the entire object graph is corrupted and saving will lead to data loss? NSAssert()
on it as a warning to the caller but press on (silently doing nothing)?
Right now I'm simply directly assigning my desired NS[Mutable]Set
in that case, like so:
- (void)setChildren:(NSSet*)value_ {
NSMutableSet *mutableRelationshipSet = [[[self primitiveValueForKey:@"children"] mutableCopy] autorelease];
if (mutableRelationshipSet) {
[mutableRelationshipSet setSet:value_];
[self setPrimitiveValue:mutableRelationshipSet forKey:@"children"];
} else {
[self setPrimitiveValue:value_ forKey:@"children"];
}
}
Is that wrong?
Just mutate the return value of -primitiveValueForKey:
as a mutable set, trusting that its return value will do the right thing.
Be sure to also use -willChangeValueForKey:withSetMutation:usingObjects:
and -didChangeValueForKey:withSetMutation:usingObjects:
around your manipulation; you didn't show this in your above code.
- (void)setChildren:(NSSet *)value {
[self willChangeValueForKey:@"children" withSetMutation:NSKeyValueSetSetMutation usingObjects:value];
NSMutableSet *primitiveValue = [self primitiveValueForKey:@"children"];
[primitiveValue setSet:value];
[self didChangeValueForKey:@"children" withSetMutation:NSKeyValueSetSetMutation usingObjects:value];
}
If you can target Leopard, you don't have to worry about this; you can use Core Data's built-in property support instead:
#import <CoreData/CoreData.h>
@interface Folder : NSManagedObject
@property (readwrite, retain) NSSet *children;
@end
@implementation Folder
@dynamic children;
@end
Core Data will generate not only a getter/setter pair for the children
property but the mutable-set accessors as well, so you can use -mutableSetValueForKey:
on it and manipulate the result with a minimum of overhead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With