problem with NSOutlineView, NSTreeController, core data, bindings, keyPath, and undo
problem with NSOutlineView, NSTreeController, core data, bindings, keyPath, and undo
- Subject: problem with NSOutlineView, NSTreeController, core data, bindings, keyPath, and undo
- From: Ken Victor <email@hidden>
- Date: Mon, 25 Jun 2007 16:50:05 -0700
i've got an outline view bound to a tree controller. the content set
of the tree controller is programmatically bound to a mutable set
(proxySet) in my model. objects are added and removed from the
model's mutable set via addProxySetObject and removeProxySetObject.
the actual objects, KVOutlineProxyObject, in proxySet are subclassed
from NSObject and contain various instances of objects subclassed
from NSMangagedObject. the reason for this approach is that it allows
me to use heterogeneous objects in my outline view (as others have
pointed out previously in posts here.)
additionally, several columns in the outline are bound (in IB) via
the tree controller to a property of other objects from a to-one
relationship of the first object. eg, one column is bound to:
treeController.arrangedObjects.sister.name
where sister is a to-on relationship of the object for the row. ie,
bound via a keyPath, not a "simple" key.
when it is time to add a new item to the outline, i first create the
new (subclass of) NSManagedObject, create a KVOutlineProxyObject to
wrap the (subclass of) NSManagedObject and either
a) link it into my tree of KVOutlineProxyObjects and do a
-[NSOutline expandItem: expandChildren:] on the parent of the new
object; or
b) call my model object's addProxySetObject (for top level objects)
this all works beautifully!
i believe this all works (summarily) as follows (and the reason i
describe this here is because i believe it is relevant to the
problems i have with undo, discussed below)
i create my subclass of NSManagedObject for the new object
and set its properties and relationships; lets call this new instance
moA. and lets say it has a sister to-one relationship to an other
subclass of NSManagedObject, sisterOfA
i create my "wrapper" KVOutlineProxyObject for moA; lets call
this kvA; kvA has an iVar named realObject, with appropriate
accessors/mutators
[kvA valueForKey: @"sister"] will return sisterOfA (via
[[self realObject] sister])
cocoa learns about kvA either via expandItem... or addProxySetObject
cocoa adds an observer to kvA for the keyPath: sister.name
cocoa adds an observer to sisterOfA for the keyPath: name
but... if undo is called...
core data undoes moA so it no longer has a valid sister
to-one relationship
i either unlink kvA from my tree and call [outline reload
data] or removeProxySetObject (if it was a top level entry)
cocoa removes the observer of kvA for the keyPath: sister.name
cocoa wants to remove the observer of sisterOfA for the
keyPath: name, but is unable to because when it calls valueForKey:
@"sister" of kvA, kvA is unable to find the sister of moA because
core data has already undone the relationship
if i then subsequently close the window containing the outline, cocoa
will dealloc its observers (since observers aren't retained by the
observee). if i then close my document, i get a zombie bug when the
NSManagedObjectContext is deallocated because there is a deallocated
observer still registered for the keyPath: name of sisterOfA.
specifically, i get:
Selector 'observeValueForKeyPath:ofObject:change:context:'
sent to dealloced instance 0x27b08fc0 of class
NSKeyValueObservationForwarder
and when i examine this with gdb, this is happening because of a
didChangeValueForKey: @"name" of sisterOfA when it is turned into a
fault as a result of deallocating the managed object context (see
stack trace below).
i believe i can work around this by creating an extra accessor:
sisterName and binding in IB to this (instead of to sister.name), but
that feels dirty to me! :-(
i don't doubt that i'm doing something wrong, and/or that my analysis
is incorrect. however, having spent almost 3 full days on this now,
i'd like to know if anyone can confirm or deny my analysis and/or
suggest some approach other than providing "phony" keys instead of
using a keypath.
thanx,
ken
#0 0x928d68b4 in -[_NSZombie methodSignatureForSelector:]
#1 0x927fa2f4 in -[NSObject(NSForwardInvocation) forward::]
#2 0x90a5ccc1 in _objc_msgForward
#3 0x927e3344 in -[NSObject(NSKeyValueObserverNotification)
didChangeValueForKey:]
#4 0x93cd5038 in -[NSManagedObject didChangeValueForKey:]
#5 0x93cc09c8 in -[NSFaultHandler turnObject:intoFaultWithContext:]
#6 0x93cc0558 in -[NSManagedObjectContext(_NSInternalAdditions)
_disposeObjects:count:notifyParent:]
#7 0x93cc0067 in -[NSManagedObjectContext(_NSInternalAdditions) _dispose:]
#8 0x93cbfcf7 in -[NSManagedObjectContext dealloc]
#9 0x9280d444 in __NSFireMainThreadPerform
#10 0x90860389 in __CFRunLoopPerformPerform
#11 0x9082cf92 in CFRunLoopRunSpecific
#12 0x9082cace in CFRunLoopRunInMode
#13 0x92dec8d8 in RunCurrentEventLoopInMode
#14 0x92debf19 in ReceiveNextEventCommon
#15 0x92debe39 in BlockUntilNextEventMatchingListInMode
#16 0x93292465 in _DPSNextEvent
#17 0x93292056 in -[NSApplication
nextEventMatchingMask:untilDate:inMode:dequeue:]
#18 0x9328bddb in -[NSApplication run]
#19 0x9327fd2f in NSApplicationMain
#20 0x00002918 in main at main.m:12
_______________________________________________
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