[Openmcl-devel] object classes and nib files (a clue and a puzzle)
alexcrain at mail.widgetworks.com
Mon Jan 3 09:11:19 PST 2005
On Jan 2, 2005, at 6:03 PM, Dan Knapp wrote:
>> I'm having trouble loading an OBJC class from a nib file.
>> I have a class HemlockTextView that inherits NSTextView and I do
>> ? (make-instance 'ns:ns-window-controller :with-window-nib-name
> There is an example of how to do this at the end of:
> 10.2. Instantiating Objective-C Objects
> NSWindowController is something of a special case. It requires the
> parameter. The object passed as the :owner should be an allocated but
> uninitialized instance of the same class as the one defined in the NIB
> file as
> the owner. It is then initialized to be identical to the saved object.
> Things do appear to work if you leave :owner off, but it's behaviour
> by Apple.
I found this:
- (id)initWithWindowNibName:(NSString *)windowNibName
Returns an NSWindowController object initialized with windowNibName,
the name of the nib file (minus the “.nib” extension) that archives the
receiver’s window. The windowNibName argument cannot be nil. Sets the
owner of the nib file to the receiver. The default initialization turns
on cascading, sets the shouldCloseDocument flag to NO, and sets the
autosave name for the window’s frame to an empty string.
which seems to suggest that you are allowed to drop the :owner. I've
also been digging into how nib files work (see below) and I see that
doesn't normal invoke an initialization callback so any lisp side
initialization is going to have to be done by make-instance or the
'alloc method. Maybe I'm missing something but I can't see why it
wouldn't work (and it does seem to work, since I've been doing lots of
coding this way).
Thinking about this did help me understand what was going on, however.
With objc classes, the objc part gets initialized by the AppKit code,
but the lisp part has to be initialized by ALLOCATE-INSTANCE. Normally
this happens transparently when MAKE-INSTANCE calls ALLOCATE-INSTANCE
and then sends the 'alloc and 'init messages to AppKit to initialize
the other side.
Loading instances from a nib file does not invoke MAKE-INSTANCE, so
ALLOCATE-INSTANCE is not invoked either. What you get is a lisp object
that correctly maps to a valid OBJC object but has no lisp guts.
This works fine for pure OBJC classes because the lisp slots don't
really exist anyway and accessing a slot gets magically turned into an
AppKit call. If a class has real lisp slots (not :foreign-type
definitions), however, then you end up with something that looks like a
class, receives OBJC messages but generates errors if the lisp slots
are accessed because SLOT-BOUNDP can't locate the slot definition.
My hack was to make %OBJC-DOMAIN-SLOTS-VECTOR do slot vector
initialization on demand.
;; pulled from ALLOCATE-iNSTANCE
(defun allocate-slot-vector-and-register-instance (instance class)
(let* ((raw-ptr (raw-macptr-for-instance instance))
(slot-vector (create-foreign-instance-slot-vector class)))
(setf (slot-vector.instance slot-vector) raw-ptr)
(setf (gethash raw-ptr *objc-object-slot-vectors*) slot-vector))
(register-canonical-objc-instance instance raw-ptr)))
(defun %objc-domain-slots-vector (p)
(let* ((type (%macptr-type p))
(flags (ldb objc-type-flags type))
(index (ldb objc-type-index type)))
(declare (fixnum type flags index))
(#.objc-flag-instance (or (gethash p *objc-object-slot-vectors*)
; try to allocate the slot vector on demand
(allocate-slot-vector-and-register-instance p (class-of p))
(error "~s has no slots." p)))
(#.objc-flag-class (id->objc-class-slots-vector index))
(#.objc-flag-metaclass (id->objc-metaclass-slots-vector index)))))
This doesn't really fix the problem, though, because
INITIALIZE-INSTANCE doesn't get called, either.
I think that the right thing to do would be to call ALLOCATE-INSTANCE
and INITIALIZE-INSTANCE whenever we try to access and unitialized OBJC
instance, but I'm not clear on where the test would go.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Size: 5248 bytes
Desc: not available
More information about the Openmcl-devel