[Openmcl-devel] Trouble defining ObjC classes with struct slots
Gary Byers
gb at clozure.com
Wed May 23 15:45:54 PDT 2007
On Wed, 23 May 2007, Daniel Dickison wrote:
> I'm trying to create an Objective-C class in OpenMCL via the bridge
> which has a couple of NSPoint slots, and I'm running into a couple of
> problems. I'm not sure if the following behaviors are intended, but
> they sure stumped me for a while!
>
> 1. If I define the slot to have a :foreign-type of :<NSP>oint, then
> when I access the slot I get a generic foreign pointer which is not
> recognized as an :<NSP>oint. Example:
>
> (defclass a-point (ns:ns-object)
> ((point :foreign-type :<NSP>oint))
> (:metaclass ns:+ns-object))
>
> (setf p (make-instance 'a-point))
> (ns:ns-point-p (slot-value p 'point))
> ==> nil
>
> This means I can't use functions like ns:ns-point-x with the slot,
> which in inconvenient but work-aroundable using (pref (slot-value p
> 'point) :<NSP>oint.x). Is there a way to convince the runtime that
> these foreign slots are in fact NSPoints?
There should be something like
(ASSERT-FOREIGN-POINTER_TYPE <p> <foreign-type>),
(which does what RLET and MAKE-RECORD do), and SLOT-VALUE (which pretty
much has to cons up a MACPTR in cases like this).
;;; This would be useful outside of ObjC and should probably be
;;; exported from CCL.
(in-package "CCL") ;
(defmacro assert-foreign-pointer-type (pointer foreign-type)
(let* ((p (gensym)))
`(let* ((,p ,pointer))
(%set-macptr-type
,p
(foreign-type-ordinal
(load-time-value (%foreign-type-or-record ',foreign-type))))
,p)))
;;; We'd like SLOT-VALUE to assert that the pointer it returns points
;;; to an NSRect; until it does so:
(assert-foreign-pointer-type (slot-value (make-instance 'a-point) 'point)
:<NSP>oint)
#<NS-POINT 5.180654D-318,0 (#x122B56A0) #x300041AA69DD>
>
>
> 2. If I define the slot to be a CLOS slot (i.e. no :foreign-type
> option), then I can store NSPoints in the slot and get back NSPoints
> as expected, BUT, any initialization I do during the ObjC -init
> method gets overridden by the :initform. It seems that CLOS slots
> get re-initialized after the ObjC -init method runs, so the ObjC
> initializations get wiped out. Example:
>
> (defclass b-point (ns:ns-object)
> ((point :initform (ns:make-ns-point 1.0 2.0)))
> (:Metaclass ns:+ns-object))
>
> (objc:defmethod (#/init :id) ((self b-point))
> (format t "Before: ~A " (slot-value self 'point))
> (setf (slot-value self 'point) (ns:make-ns-point 3.0 4.0))
> (format t "After: ~A" (slot-value self 'point))
> self)
>
> (setf p (make-instance 'b-point)) ;; Before: #<NS-POINT 1,2...>
> After: #<NS-POINT 3,4...>
> (slot-value p 'point)
> ==> #<NS-POINT 1,2...>
>
> This as also work-aroundable by doing the CLOS slot initialization in
> an initialize-instance :after method, but it seems wrong to do the
> same initialization in 2 different places depending on whether Lisp
> or Objective-C created the instance.
I think that that's a bug, but there are some chicken-and-egg issues
here. (In order to be able to refer to the object's lisp slots from an
ObjC init method, it's necessary to run INITIALIZE-INSTANCE - with no
initargs - so that the slots' initforms are executed. The ObjC init
method is often called (as part of ALLOCATE-INSTANCE) by
MAKE-INSTANCE, which then turns around and does INITIALIZE-INSTANCE
with initargs. That shouldn't cause any slots to be "initialized
twice", but it's certainly unintuitive that INITIZLIZE-INSTANCE
should run twice per instance (and it probably offers ways to lose.))
The bug is that ALLOCATE-INSTANCE creates a "slots vector" for
the instance even if one was created by virtue of the fact that
a lisp slot was referenced in an ObjC #/init method.)
>
> Daniel
>
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel
>
>
More information about the Openmcl-devel
mailing list