re: setPrimitiveValue:forKey: and to-many relationships
re: setPrimitiveValue:forKey: and to-many relationships
- Subject: re: setPrimitiveValue:forKey: and to-many relationships
- From: Ben Trumbull <email@hidden>
- Date: Wed, 24 Sep 2008 18:17:08 -0700
Sean, Jon,
The documentation is correct for 10.4. On 10.5, things are more
forgiving, and you can call -setPrimitiveValue:forKey: with a public
set. We won't use that object, but we will use its contents. It does
no inverse maintenance, so unless it's part of the public setter for
the relationship, it's a pretty awful idea.
"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?
The to-many relationship object is itself a private subclass of NSSet,
so eventually will occur when someone gets back the improperly
assigned set, and tries to use it. With -mutableSetValueForKey: or
any number of other operations. "eventually == implementation
dependent behavior == answer is still no" I suppose you could write a
test case on Tiger that failed on-demand.
On Leopard, it's important to realize that you won't get back the
object you assigned if you try to do this. In general, the Xcode
template generation in the Design menu is the recommended form.
Second, providing sample code to correctly handle this case, they
write:
"first get the existing set using primitiveValueForKey: (ensure the
method does not return nil)..."
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)?
It should never return nil, unless you do something very wrong, like
try to set values in the faulting callbacks (will or
didTurnIntoFault). Within the scope of turning the object into a
fault, you should send such messages to nil (e.g. /dev/null )
Right now I'm simply directly assigning my desired NS[Mutable]Set in
that case, like so:
- (void)setChildren:(NSSet*)value_
{
[self willChangeValueForKey:@"children"];
NSMutableSet *mutableRelationshipSet = [[[self
primitiveValueForKey:@"children"] mutableCopy] autorelease];
if (mutableRelationshipSet) {
[mutableRelationshipSet setSet:value_];
[self setPrimitiveValue:mutableRelationshipSet
forKey:@"children"];
} else {
[self setPrimitiveValue:value_ forKey:@"children"];
}
[self didChangeValueForKey:@"children"];
}
Is that wrong?
The recommended form of implementing a custom accessor with a Core
Data property can be created in Xcode using the Design menu -> Data
Model -> Copy ObjC 2.0 Method Implementation when you have that
property(ies) selected in the model view.
You are strongly encouraged to use the built in accessor methods, and
the templates provided as much as possible. For example, this setter
will cause a lot of KVO notifications to get generated. It is very
inefficient compared to -addChildren, -removeChildren, and -
addChildrenObject, and -removeChildrenObject. Examining the template
generation for those methods should give you an idea why.
In this case, you're not doing anything custom at all, and should just
use Core Data's default -setChildren method, which you will get with a
dynamic property declaration. Actually, you get it anyway, the
property declaration just tells the compiler not to warn.
Quincey's suggestions are apt.
As repeated in the Core Data documentation, the primitive accessor
methods are intended exclusively as building blocks for the creation
of custom public accessors, and should not be used for other
purposes. The relationship maintenance (inverses) may be maintained
via KVO, so directly using the primitive setter on a relationship
without issuing the correct KVO notifications is dangerous and wrong.
- Ben
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden