Ignore:
Timestamp:
Mar 27, 2008, 10:45:37 PM (12 years ago)
Author:
mikel
Message:

added discussion of objc:defmethod and made some edits of existing docs for define-objc-method

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/source/doc/src/objc-bridge.xml

    r8896 r8908  
    515515
    516516  <sect1 id="Defining-Objective-C-Methods">
     517    <anchor id="anchor_Defining-Objective-C-Methods"/>
    517518    <title>Defining Objective-C Methods</title>
    518519    <para>In Objective-C, unlike in CLOS, every method belongs to some
     
    522523      belonging to Objective-C classes which have been defined in
    523524      Lisp.</para>
    524     <para>The macro <literal>define-objc-method</literal> is used for
    525       this.  As described in the
    526       section <link linkend="Calling-Objective-C-Methods">Calling
    527       Objective-C Methods</link>, the names of Objective-C methods are
    528       broken into pieces, each piece followed by a parameter.  The
    529       types of all parameters must be explicitly declared.</para>
    530     <para>Right now, I'm not sure how to formally describe the usage
    531       of define-objc-method, so I'm going to do it with some short
    532       examples.  Let us define a class to use in them:</para>
    533     <programlisting>
     525    <para>You can use either of two different macros to define methods
     526    on Objective-C classes. <literal>define-objc-method</literal>
     527    accepts a two-element list containing a message selector name and
     528    a class name, and a body. <literal>objc:defmethod</literal>
     529    superficially resembles the normal
     530    CLOS <literal>defmethod</literal>, but creates methods on
     531    Objective-C classes with the same restrictions as those created
     532    by <literal>define-objc-method</literal>.</para>
     533
     534    <sect2>
     535      <title>Using <literal>define-objc-method</literal></title>
     536      <para>As described in the
     537        section <link linkend="Calling-Objective-C-Methods">Calling
     538        Objective-C Methods</link>, the names of Objective-C methods
     539        are broken into pieces, each piece followed by a parameter.
     540        The types of all parameters must be explicitly
     541        declared.</para>
     542      <para>Consider a few examples, meant to illustrate the use
     543        of <literal>define-objc-method</literal>. Let us define a
     544        class to use in them:</para>
     545
     546      <programlisting>
    534547(defclass data-window-controller (ns:ns-window-controller)
    535548  ((window :foreign-type :id :accessor window)
    536549   (data :initform nil :accessor data))
    537550  (:metaclass ns:+ns-object))
    538     </programlisting>
    539     <para>There's nothing special about this class.  It inherits
    540       from ns:ns-window-controller.  It has two slots:
    541       <literal>window</literal> is a foreign slot, stored in the Objective-C
    542       world; and <literal>data</literal> is an ordinary slot, stored
    543       in the Lisp world.</para>
    544     <para>Here is an example of how to define a method which takes no
    545       arguments:</para>
    546     <programlisting>
     551      </programlisting>
     552
     553      <para>There's nothing special about this class.  It inherits from
     554        <literal>ns:ns-window-controller</literal>.  It has two slots:
     555        <literal>window</literal> is a foreign slot, stored in the Objective-C
     556        world; and <literal>data</literal> is an ordinary slot, stored
     557        in the Lisp world.</para>
     558
     559      <para>Here is an example of how to define a method which takes no
     560        arguments:</para>
     561
     562      <programlisting>
    547563(define-objc-method ((:id get-window)
    548564                     data-window-controller)
    549565    (window self))
    550     </programlisting>
    551     <para>The return type of this method is the foreign type :id,
    552       which is used for all Objective-C objects.  The name of the method is
    553       <literal>get-window</literal>.  The body of the method is the
    554       single line (window self).  The variable <literal>self</literal>
    555       is bound, within the body, to the instance which is receiving
    556       the message.  The call to <literal>window</literal> uses the
    557       CLOS accessor to get the value of the window field.</para>
    558     <para>Here's an example which takes a parameter.  Notice that
    559       the name of the method without a parameter was an ordinary
    560       symbol, but with a parameter, it's a keyword:</para>
    561     <programlisting>
     566      </programlisting>
     567
     568      <para>The return type of this method is the foreign type :id,
     569        which is used for all Objective-C objects.  The name of the
     570        method is
     571        <literal>get-window</literal>.  The body of the method is the
     572        single line <literal>(window self)</literal>.  The
     573        variable <literal>self</literal> is bound, within the body, to
     574        the instance that is receiving the message.  The call
     575        to <literal>window</literal> uses the CLOS accessor to get the
     576        value of the window field.</para>
     577
     578      <para>Here's an example that takes a parameter.  Notice that the
     579        name of the method without a parameter was an ordinary symbol,
     580        but with a parameter, it's a keyword:</para>
     581
     582      <programlisting>
    562583(define-objc-method ((:id :init-with-multiplier (:int multiplier))
    563584                     data-window-controller)
     
    567588          (* i multiplier)))
    568589  self)
    569     </programlisting>
    570     <para>To Objective-C code which uses the class, the name of this
    571       method is "initWithMultiplier:".  The name of the parameter is
    572       <literal>multiplier</literal>, and its type is :int.  The body
    573       of the method does some meaningless things.  Then it returns
    574       <literal>self</literal>, because this is an initialization
    575       method.</para>
    576     <para>Here's an example with more than one parameter:</para>
    577     <programlisting>
     590      </programlisting>
     591
     592      <para>To Objective-C code that uses the class, the name of this
     593        method is <literal>initWithMultiplier:</literal>.  The name of
     594        the parameter is
     595        <literal>multiplier</literal>, and its type
     596        is <literal>:int</literal>.  The body of the method does some
     597        meaningless things.  Then it returns
     598        <literal>self</literal>, because this is an initialization
     599        method.</para>
     600
     601      <para>Here's an example with more than one parameter:</para>
     602
     603      <programlisting>
    578604(define-objc-method ((:id :init-with-multiplier (:int multiplier)
    579605                          :and-addend (:int addend))
     
    585611             addend)))
    586612  self)
    587     </programlisting>
    588     <para>To Objective-C, the name of this method is
    589       "initWithMultiplier:andAddend:".  Both parameters are of type
    590       :int; the first is named <literal>multiplier</literal>, and the
    591       second is <literal>addend</literal>.  Again, the method returns
    592       <literal>self</literal>.</para>
    593     <para>Here is a method which does not return any value, a
    594       so-called "void method".  Where our other methods said :id, this
    595       one says :void for the return type:</para>
    596     <programlisting>
     613      </programlisting>
     614
     615      <para>To Objective-C, the name of this method is
     616        <literal>initWithMultiplier:andAddend:</literal>.  Both
     617        parameters are of type <literal>:int</literal>; the first is
     618        named <literal>multiplier</literal>, and the second
     619        is <literal>addend</literal>.  Again, the method returns
     620        <literal>self</literal>.</para>
     621
     622      <para>Here is a method that does not return any value, a so-called
     623        "void method".  Where our other methods
     624        said <literal>:id</literal>, this one
     625        says <literal>:void</literal> for the return type:</para>
     626
     627      <programlisting>
    597628(define-objc-method ((:void :take-action (:id sender))
    598629                     data-window-controller)
     
    601632    (setf (aref (data self) i)
    602633          (- (aref (data self) i)))))
    603     </programlisting>
    604     <para>This method would be called "takeAction:" in Objective-C.  The
    605       convention for methods that are going to be used as Cocoa
    606       actions is that they take one parameter, which is the object
    607       responsible for triggering the action.  However, this method
    608       doesn't actually need to use that parameter, so it explicitly
    609       ignores it to avoid a compiler warning.  As promised, the method
    610       doesn't return any value.</para>
    611     <para>There is also an alternate syntax, illustrated here.  The
    612       following two method definitions are equivalent:</para>
    613     <programlisting>
     634      </programlisting>
     635
     636      <para>This method would be called <literal>takeAction:</literal>
     637        in Objective-C.  The convention for methods that are going to be
     638        used as Cocoa actions is that they take one parameter, which is
     639        the object responsible for triggering the action.  However, this
     640        method doesn't actually need to use that parameter, so it
     641        explicitly ignores it to avoid a compiler warning.  As promised,
     642        the method doesn't return any value.</para>
     643
     644      <para>There is also an alternate syntax, illustrated here.  The
     645        following two method definitions are equivalent:</para>
     646
     647      <programlisting>
    614648(define-objc-method ("applicationShouldTerminate:"
    615649                     "LispApplicationDelegate")
     
    623657    (declare (ignore sender))
    624658    nil)
    625     </programlisting>
     659      </programlisting>
     660      </sect2>
     661
     662    <sect2>
     663      <anchor id="anchor_Using-objc-defmethod"/>
     664
     665          <title>Using <literal>objc:defmethod</literal></title>
     666
     667      <para>The macro <literal>OBJC:DEFMETHOD</literal> can be used to
     668        define Objective-C methods.  It looks superficially like
     669        <literal>CL:DEFMETHOD</literal> in some respects.</para>
     670
     671      <para>Its syntax is</para>
     672
     673      <programlisting>
     674(OBC:DEFMETHOD name-and-result-type
     675               ((receiver-arg-and-class) &rest; other-args)
     676      &body; body)
     677      </programlisting>
     678
     679      <para><literal>name-and-result-type</literal> is either an
     680        Objective-C message name, for methods that return a value of
     681        type <literal>:ID</literal>, or a list containing an
     682        Objective-C message name and a foreign type specifier for
     683        methods with a different foreign result type.</para>
     684
     685      <para><literal>receiver-arg-and-class</literal> is a two-element
     686        list whose first element is a variable name and whose second
     687        element is the Lisp name of an Objective-C class or metaclass.
     688        The receiver variable name can be any bindable lisp variable
     689        name, but <literal>SELF</literal> might be a reasonable
     690        choice.  The receiver variable is declared to be "unsettable";
     691        i.e., it is an error to try to change the value of the
     692        receiver in the body of the method definition.</para>
     693
     694      <para><literal>other-args</literal> are either variable names
     695            (denoting parameters of type <literal>:ID</literal>) or
     696            2-element lists whose first element is a variable name and
     697            whose second element is a foreign type specifier.</para>
     698
     699      <para>Consider this example:</para>
     700
     701      <programlisting>
     702(objc:defmethod (#/characterAtIndex: :unichar)
     703    ((self hemlock-buffer-string) (index :&lt;NSUI&gt;nteger))
     704  ...)
     705      </programlisting>
     706
     707      <para>The method <literal>characterAtIndex:</literal>, when
     708        invoked on an object of
     709        class <literal>HEMLOCK-BUFFER-STRING</literal> with an
     710        additional argument of
     711        type <literal>:&lt;NSU&gt;integer</literal> returns a value of
     712        type
     713        <literal>:unichar</literal>.</para>
     714
     715      <para>Arguments that wind up as some pointer type other
     716        than <literal>:ID</literal> (e.g. pointers, records passed by
     717        value) are represented as typed foreign pointers, so that the
     718        higher-level, type-checking accessors can be used on arguments
     719        of
     720        type <literal>:ns-rect</literal>, <literal>:ns-point</literal>,
     721        and so on.</para>
     722
     723      <para>Within the body of methods defined
     724        via <literal>OBJC:DEFMETHOD</literal>, the local function
     725        <literal>CL:CALL-NEXT-METHOD</literal> is defined.  It isn't
     726        quite as general as <literal>CL:CALL-NEXT-METHOD</literal> is
     727        when used in a CLOS method, but it has some of the same
     728        semantics.  It accepts as many arguments as are present in the
     729        containing method's <literal>other-args</literal> list and
     730        invokes version of the containing method that would have been
     731        invoked on instances of the receiver's class's superclass with
     732        the receiver and other provided arguments.  (The idiom of
     733        passing the current method's arguments to the next method is
     734        common enough that the <literal>CALL-NEXT-METHOD</literal> in
     735        <literal>OBJC:DEFMETHODs</literal> should probably do this if
     736        it receives no arguments.)</para>
     737
     738      <para>A method defined via <literal>OBJC:DEFMETHOD</literal>
     739        that returns a structure "by value" can do so by returning a
     740        record created via <literal>MAKE-GCABLE-RECORD</literal>, by
     741        returning the value returned
     742        via <literal>CALL-NEXT-METHOD</literal>, or by other similar
     743        means. Behind the scenes, there may be a pre-allocated
     744        instance of the record type (used to support native
     745        structure-return conventions), and any value returned by the
     746        method body will be copied to this internal record instance.
     747        Within the body of a method defined
     748        with <literal>OBJC:DEFMETHOD</literal> that's declared to
     749        return a structure type, the local macro
     750        <literal>OBJC:RETURNING-FOREIGN-STRUCT</literal> can be used
     751        to access the internal structure. For example:</para>
     752
     753       <programlisting>
     754(objc:defmethod (#/reallyTinyRectangleAtPoint: :ns-rect)
     755  ((self really-tiny-view) (where :ns-point))
     756  (objc:returning-foreign-struct (r)
     757    (ns:init-ns-rect r (ns:ns-point-x where) (ns:ns-point-y where)
     758                        single-float-epsilon single-float-epsilon)
     759    r))
     760       </programlisting>
     761     
     762    </sect2>
     763
    626764    <sect2 id="Method-Redefinition-Constraints">
    627765          <title>Method Redefinition Constraints</title>
Note: See TracChangeset for help on using the changeset viewer.