All Manuals > LispWorks Objective-C and Cocoa Interface User Guide and Reference Manual > 1 Introduction to the Objective-C Interface

1.3 Invoking Objective-C methods

Objective-C methods are associated with Objective-C objects or classes and are invoked by name with a specific set of arguments.

1.3.1 Simple calls to instance and class methods

The function invoke is used to call most methods (but see 1.3.4 Invoking a method that returns a boolean, 1.3.5 Invoking a method that returns a structure and 1.3.6 Invoking a method that returns a string or array for ways of calling more complex methods). This function has two required arguments:

The remaining arguments are passed to the method in the specified order. See 1.3.3 Special argument and result conversion for information about how the arguments are converted to FLI values.

For example, a call in Objective-C such as:

[window close]

would be written using invoke as:

(invoke window "close")

In addition, invoke can be used to call class methods for specifically named classes. This is done by passing a string naming the Objective-C class instead of the object.

For example, a class method call in Objective-C such as:

[NSObject alloc]

would be written using invoke as:

(invoke "NSObject" "alloc")

1.3.2 Method naming

Methods in Objective-C have compound names that describe their main name and any arguments. Functions like invoke that need a method name expect a string with all the name components concatenated together with no spaces.

For example, a call in Objective-C such as:

[box setWidth:10 height:20]

would be written using invoke as:

(invoke box "setWidth:height:" 10 20)

1.3.3 Special argument and result conversion

Since the LispWorks Objective-C interface is an extension of the FLI, most conversion of arguments and results is handled as specified in the Foreign Language Interface User Guide and Reference Manual. There are a few exceptions to make it easier to invoke methods with certain commonly used Objective-C classes and structures as shown in the Special argument and result conversion for invoke. See the specification of invoke for full details.

Special argument and result conversion for invoke
TypeSpecial argument behaviorSpecial result behavior

NSRect

Allows a vector to be passed.

Converts to a vector.

NSPoint

Allows a vector to be passed.

Converts to a vector.

NSSize

Allows a vector to be passed.

Converts to a vector.

NSRange

Allow a cons to be passed.

Converts to a cons.

BOOL

Allow nil or t to be passed.

None. See 1.3.4 Invoking a method that returns a boolean.

id

Depending on the Objective-C class, allows automatic conversion of strings and arrays.

None. See 1.3.6 Invoking a method that returns a string or array.

Class

Allows a string to be passed.

None.

char *

Allows a string to be passed.

Converts to a string.

1.3.4 Invoking a method that returns a boolean

When a method has return type BOOL on a Macintosh with an Intel CPU, the value is converted to the integer 0 or 1 because Objective-C cannot distinguish this type from the other integer types. Often it is more convenient to receive the value as a Lisp boolean and this can be done by using the function invoke-bool, which returns nil or t.

For example, a call in Objective-C such as:

[box isSquare] ? 1 : 2

could be written using invoke-bool as:

(if (invoke-bool box "isSquare") 1 2)

1.3.5 Invoking a method that returns a structure

As mentioned in 1.3.3 Special argument and result conversion, when invoke is used with a method whose return type is one of the structure types listed in Special argument and result conversion for invoke, such as NSRect, a vector or cons containing the fields of the structure is returned. For other structure types defined with define-objc-struct, the function invoke-into must be used to call the method. This takes the same arguments as invoke, except that there is an extra initial argument, result, which should be a pointer to a foreign structure of the appropriate type for the method. When the method returns, the value is copied into this structure.

For example, a call in Objective-C such as:

{
  NSRect rect = [box frame];
  ...
}

could be written using invoke-into as:

(fli:with-dynamic-foreign-objects ((rect cocoa:ns-rect))
  (objc:invoke-into rect box "frame")
  ...)

In addition, for the structure return types mentioned in Special argument and result conversion for invoke, an appropriately sized vector or cons can be passed as result and this is filled with the field values.

For example, the above call could also be written using invoke-into as:

(let ((rect (make-array 4)))
  (objc:invoke-into rect box "frame")
  ...)

1.3.6 Invoking a method that returns a string or array

The Objective-C classes NSString and NSArray are used extensively in Cocoa to represent strings and arrays of various objects. When a method that returns these types is called with invoke, the result is a foreign pointer of type objc-object-pointer as for other classes.

In order to obtain a more useful Lisp value, invoke-into can be used by specifying a type as the extra initial argument. For a method that returns NSString, the symbol string can be specified to cause the foreign object to be converted to a string. For a method that returns NSArray, the symbol array can be specified and the foreign object is converted to an array of foreign pointers. Alternatively a type such as (array string) can be specified and the foreign object is converted to an array of strings.

For example, the form:

(invoke object "description")

will return a foreign pointer, whereas the form:

(invoke-into 'string object "description")

will return a string.

1.3.7 Invoking a method that returns values by reference

Values are returned by reference in Objective-C by passing a pointer to memory where the result should be stored, just like in the C language. The Objective-C interface in Lisp works similarly, using the standard FLI constructs for this.

For example, an Objective-C method declared as:

- (void)getValueInto:(int *)result;

might called from Objective-C like this:

int getResult(MyObject *object)
{
  int result;
  [object getValueInto:&result];
  return result;
}

The equivalent call from Lisp can be made like this:

(defun get-result (object)
  (fli:with-dynamic-foreign-objects ((result-value :int))
    (objc:invoke object "getValueInto:" result-value)
    (fli:dereference result-value)))

The same technique applies to in/out arguments, but adding code to initialize the dynamic foreign object before calling the method.

1.3.8 Invoking a method that uses vector types

In order to invoke a method that uses vector types (see "Vector types" in the Foreign Language Interface User Guide and Reference Manual), calls to invoke etc need to specify the argument and result types of the method. This is because vector types are not compatible with the Objective-C Runtime type encoding API.

This is done by passing a list as the method argument. For example, yuo can invoke the following methods of MDLTransform in the Model I/O API:

;; Call -(vector_float3)translationAtTime:(NSTimeInterval)time;
(invoke ptr '("translationAtTime:"
              (:double)
              :result-type fli:vector-float3)
        20d0)
 
;; -(void)setTranslation:(vector_float3)translation
;;         forTime:(NSTimeInterval)time;
(objc:invoke ptr '("setTranslation:forTime:"
                   (fli:vector-float3 :double))
             #(22d0 32d0 42d0)
             20d0)

1.3.9 Determining whether a method exists

In some cases, an Objective-C class might have a method that is optionally implemented and invoke will signal an error if the method is missing for a particular object. To determine whether a method is implemented, call the function can-invoke-p with the foreign object pointer or class name and the name of the method.

For example, a call in Objective-C such as:

[foo respondsToSelector:@selector(frame)]

could be written using can-invoke-p as:

(can-invoke-p foo "frame")

1.3.10 Memory management

Objective-C uses reference counting for its memory management and also provides a mechanism for decrementing the reference count of an object when control returns to the event loop or some other well-defined point.

The following functions are direct equivalents of the memory management methods in the NSObject class:

Helper functions for memory management
FunctionMethod in NSObject

retain

retain

retain-count

retainCount

release

release

autorelease

autorelease

In addition, the function make-autorelease-pool and the macro with-autorelease-pool can be used to make autorelease pools if the standard one in the event loop is not available.

1.3.11 Selectors

Some Objective-C methods have arguments or values of type SEL, which is a pointer type used to represent selectors. These can be used in Lisp as foreign pointers of type sel, which can be obtained from a string by calling coerce-to-selector. The function selector-name can be used to find the name of a selector.

For example, a call in Objective-C such as:

[foo respondsToSelector:@selector(frame)]

could be written using can-invoke-p as in 1.3.9 Determining whether a method exists or using selectors as follows:

(invoke foo "respondsToSelector:" (coerce-to-selector "frame"))

If *selector* is bound to the result of calling:

(coerce-to-selector "frame")

then:

(selector-name *selector*)

will return the string "frame".


LispWorks Objective-C and Cocoa Interface User Guide and Reference Manual - 01 Dec 2021 19:38:32