Previous Section Next Section Table of Contents Glossary Index

Chapter 14. The Objective-C Bridge

14.5. Defining Objective-C Classes

You can define your own foreign classes, which can then be passed to foreign functions; the methods which you implement in Lisp will be made available to the foreign code as callbacks.

You can also define subclasses of existing classes, implementing your subclass in Lisp even though the parent class was in Objective C. One such subclass is CCL::NS-LISP-STRING. It is also particularly useful to make subclasses of NS-WINDOW-CONTROLLER.

We can use the MOP to define new Objective-C classes, but we have to do something a little funny: the :METACLASS that we'd want to use in a DEFCLASS option generally doesn't exist until we've created the class (recall that Objective-C classes have, for the sake of argument, unique and private metaclasses.) We can sort of sleaze our way around this by specifying a known Objective-C metaclass object name as the value of the DEFCLASS :METACLASS object; the metaclass of the root class NS:NS-OBJECT, NS:+NS-OBJECT, makes a good choice. To make a subclass of NS:NS-WINDOW (that, for simplicity's sake, doesn't define any new slots), we could do:

(defclass example-window (ns:ns-window)
  (:metaclass ns:+ns-object))

That'll create a new Objective-C class named EXAMPLE-WINDOW whose metaclass is the class named +EXAMPLE-WINDOW. The class will be an object of type OBJC:OBJC-CLASS, and the metaclass will be of type OBJC:OBJC-METACLASS. EXAMPLE-WINDOW will be a subclass of NS-WINDOW.

14.5.1. Defining classes with foreign slots

If a slot specification in an Objective-C class definition contains the keyword :FOREIGN-TYPE, the slot will be a "foreign slot" (i.e. an Objective-C instance variable). Be aware that it is an error to redefine an Objective-C class so that its foreign slots change in any way, and Clozure CL doesn't do anything consistent when you try to.

The value of the :FOREIGN-TYPE initarg should be a foreign type specifier. For example, if we wanted (for some reason) to define a subclass of NS:NS-WINDOW that kept track of the number of key events it had received (and needed an instance variable to keep that information in), we could say:

(defclass key-event-counting-window (ns:ns-window)
  ((key-event-count :foreign-type :int
                    :initform 0
                    :accessor window-key-event-count))
  (:metaclass ns:+ns-object))

Foreign slots are always SLOT-BOUNDP, and the initform above is redundant: foreign slots are initialized to binary 0.

14.5.2. Defining classes with Lisp slots

A slot specification in an Objective-C class definition that doesn't contain the :FOREIGN-TYPE initarg defines a pretty-much normal lisp slot that'll happen to be associated with "an instance of a foreign class". For instance:

(defclass hemlock-buffer-string (ns:ns-string)
  ((hemlock-buffer :type hi::hemlock-buffer
                   :initform hi::%make-hemlock-buffer
                   :accessor string-hemlock-buffer))
  (:metaclass ns:+ns-object))

As one might expect, this has memory-management implications: we have to maintain an association between a MACPTR and a set of lisp objects (its slots) as long as the Objective-C instance exists, and we have to ensure that the Objective-C instance exists (does not have its -dealloc method called) while lisp is trying to think of it as a first-class object that can't be "deallocated" while it's still possible to reference it. Associating one or more lisp objects with a foreign instance is something that's often very useful; if you were to do this "by hand", you'd have to face many of the same memory-management issues.

Previous Section Next Section Table of Contents Glossary Index