[Openmcl-devel] NSWindow deallocation seems to work differently in CCL then it does in an XCode based application
gb at clozure.com
Fri Dec 16 16:21:23 PST 2011
There are two significant differences between the lisp version of your
code and the ObjC version:
1) In the lisp version, some ObjC methods are called by CCL's FFI.
2) In the lisp version, you create the window and view interactively
in the listener thread; in the ObjC version, everything happens on
the event thread.
The first of these differences could theoretically be significant, but
it's very hard to think of ways in which "being called by CCL's FFI"
would affect things, aside from an outright bug in the FFI.
It's not at all hard to imagine that the second difference causes subtly
different memory-management behavior than would occur if the window/view
creation and initialization happened on the main thread, and that seems
to be the issue in your example. If you create the window and view and
install the view on the event thread, the window will get released when it's
Most Cocoa GUI objects expect (explicitly or otherwise) to be created
(and, for the most part, used) on the main event thread. Some things
work to varying degrees when done from another thread; you found a case
where something almost works but it isn't quite right.
CCL is involved in this to the extent that it makes it fairly easy to
type ObjC method calls into a listener window (or evaluate forms containing
such calls from an editor window, or LOAD them from a file ...) It's hard
to see how it's otherwise involved.
On Fri, 16 Dec 2011, Michael Minerva wrote:
> I have been trying to figure out why some of our Cocoa objects do not get properly
> decollated and I created a simple example in CCL that seems to be at the heart of
> my problem:
> (defclass TRASH-WINDOW (ns:ns-window)
> ??(:metaclass ns:+ns-object
> ? ? ?:documentation "delegate object receiving window events"))
> (objc:defmethod (#/dealloc :void) ((Self trash-window))
> ??(print "DEALLOC TRASH WINDOW!!")
> (defparameter *window* (make-instance trash-window
> ?? ? ? ? ? ? ? ? ? ? ? ? :style-mask (logior?
> ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #$NSTitledWindowMask
> ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?#$NSClosableWindowMask
> ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #$NSMiniaturizableWindowMask)
> ?? ? ? ? ? ? ? ? ? ? ? ? :backing ? ? #$NSBackingStoreBuffered
> ?? ? ? ? ? ? ? ? ? ? ? ? :defer t))
> (defparameter *image-view* (make-instance ns:ns-image-view))
> (#/setContentView: *window* *image-view*)
> (#/orderFront: *window* nil)
> If you run this little example it will create a window with an NSImageView inside
> and show it, so far so good. ?Now when I close this window I am a little surprised
> to see that the #/dealloc method of my trash-window never gets called. ?
> A few other notes:?
> ? If I do not call?(#/setContentView: *window* *image-view*) the window is
> deallocated with no problems
> ? If we set the content view to be a normal NSView and then close the window it is
> released/deallocated as expected
> ? This problem is not specific to the NSImageView being the window's content view.
> ?If I create an NSView and an NSImageView then set the NSView to be the NSWindow's
> content view and make the NSImagevVew a subview of the NSView then close this
> window, dealloc is still not called.
> So when I found all this I decided it must be some oddity of Cocoa so I decided to
> do the same sort of thing in an XCode/Cocoa example before trying to consult the
> Cocoa gurus, but to my surprise, my XCode example seems to behave differently:
> // Test Code snipet
> NSRect windowFrame = NSMakeRect(500, 500, 200, 200);
> NSRect viewFrame = NSMakeRect(0, 0, 200, 200);
> NSWindow* window? = [[dealloc_window alloc] initWithContentRect:windowFrame
> styleMask:NSTitledWindowMask | NSClosableWindowMask |NSMiniaturizableWindowMask
> NSImageView* imageView = [[NSImageView alloc] initWithFrame:viewFrame];
> [window setContentView:imageView];
> [window orderFront:nil];
> // snipet from the class "dealloc_window"
> - (void) dealloc
> ? ? printf("DEALLOC");
> ? ? [super dealloc];
> When I ran this example which programmatically creates an NSWindow with an
> NSImageView as its content view and then close the NSWidnow, strangely dealloc IS
> called. ?It seems to be that these two examples are basically the same but seem to
> exhibit very different behavior. ?Anyone have any clues about what could be going
> on here?
More information about the Openmcl-devel