This egg provides a basic interface to Objective C from Scheme. You can invoke class and instance methods, access instance variables, and define Objective C classes directly in Scheme.
Method invocation
Sends the message KEYWORD1 ARGUMENT1 ... to RECEIVER, which is an objc:instance or objc:class object. This follows the normal Objective C syntax, so the call (objc myRect setWidth: 15.0 height: 20.0) invokes the method setWidth:height: on myRect, with arguments 15.0 and 20.0. If the method has no arguments, use a symbol instead of a keyword: (objc NSScanner alloc).
Identical to (objc RECEIVER KEYWORD1 ARGUMENT1 ...), but allows callbacks from Objective C into Scheme.
An abbreviation for (objc/safe RECEIVER KEYWORD ARGUMENT ...). This conservatively defaults to a 'safe' send because classes defined in Scheme are implemented as callbacks. If the receiver is prefixed with the unsafe: keyword, then this form expands into a (objc:send ...) expression instead. You can also prefix with safe:, which guarantees an objc/safe call. The ubiquitous need for safe calls may be addressed in a future release.
Instances
A wrapper for an instance of an Objective C class. The object's description method determines how this record is displayed.
Return the class of objc:instance ID, obtained by sending ID a class message. This procedure also accepts a class object, but the result will generally be the same object.
Return the raw pointer associated with objc:instance OBJ.
Create an objc:instance from a raw instance pointer (an id). Implicitly retains the object, releasing it when the objc:instance is finalized.
Strings
Constructs a new NSString from STRING. Currently assumes UTF8 encoding.
Equivalent to (objc:nsstring "...").
Converts an NSString into a Scheme string.
Instance variables
Returns the value of OBJECT's instance variable NAME (which should be a string).
Sets the value of OBJECT's instance variable NAME to VALUE.
Shorthand for (objc:ivar-ref OBJECT (symbol->string NAME)).
Shorthand for (objc:ivar-set! OBJECT (symbol->string NAME) VALUE).
Intended for use within methods, this expands to (objc:ivar-ref self "VAR").
Use (set! @var value) to set an instance variable.
Examples: (objc:ivar-set! p "x" 3) (objc:ivar-ref p "x") ; => 3 (ivar-ref p x) ; => 3 (set! @x 'hi) @x ; => 'hi
Classes
Locates the Objective C classes NAME ... and defines variables holding pointers to the class objects. NAME may be a symbol or a list of the form (VARIABLE CLASSNAME). For example, (define-objc-classes NSTextView NSTask) is equivalent to
(begin (define NSTextView (objc:string->class NSTextView)) (define NSTask (objc:string->class NSTask)))
A record representing an Objective C class.
| name | Class name as a string. |
| method-list |
List of instance methods. The format is
((NAME . SIGNATURE) ...), but may change in the future to a list of objc:method records. |
| class-method-list | List of class methods. |
| super-class | Superclass of this class (as an objc:class). |
| meta-class | Metaclass of this class (as an objc:class). |
| ivar-list | List of instance variables (as objc:instance-var records). |
Return the raw pointer associated with objc:class CLASS.
Create a class from a raw class pointer (a Class).
Look up and return the Objective C class named STRING.
Define an instance or class method in CLASS.
| CLASS | An objc:class object representing the destination class. |
| RT | The return type of the method. |
| ARGS |
((KEYWORD TYPE VAR-NAME) ...) or
SYMBOL |
| BODY | Body of a lambda comprising the method. The parameters visible inside the lambda are self (a class or instance object), sel (the method selector), and the arguments given in ARGS. |
Each list in ARGS adds a method argument of type TYPE, visible to the method body as VAR-NAME. As in Objective C, each argument is associated with a KEYWORD and each KEYWORD is combined into a method name. A bare SYMBOL can be used as the method name (instead of a list) if no arguments are expected.
TYPE should be a symbol; see the Types section for valid types. Use short typenames — DBL, not objc:DBL.
Within a method body, you can use @[super ...] to call a class or instance method of the superclass. Note: super is a reserved keyword, not a variable.
Example: (objc:define-method Rect VOID ((setWidth: DBL my-w) (height: DBL my-h)) (ivar-set! self w my-w) (ivar-set! self h my-h))
Method removal is not yet implemented, but redefining a method will override the old definition.
Defines CLASS (a symbol) with superclass SUPERCLASS (a symbol), instance variables IVARS, and methods METHODS. The new classname is imported with define-objc-classes.
SUPERCLASS is looked up for you in the runtime, so it need not be imported.
IVARS is a list of the form ((TYPE NAME) ...), where TYPE is a short typename such as INT, and NAME is a symbol representing the new variable name. Each instance of CLASS will have a separate copy of these variables.
METHODS are method definitions of the form (define-[class-]method RT ARGS . BODY), which are equivalent to calling (objc:define-[class]-method CLASS RT ARGS . BODY) using the current CLASS.
You can also use + as an alias for define-class-method and - for define-method. These correspond to Objective C method definition syntax.
Example:
(define-objc-class MyPoint NSObject ((DBL x) (DBL y))
(define-method ID init
(print "MyPoint init")
@[super init])
(- DBL getX @x)
(- DBL getY @y)
(- ID description
(sprintf "<MyPoint: (~a, ~a)>" @x @y))
(- VOID ((moveByX: DBL a) (Y: DBL b))
(set! @x (+ a @x))
(ivar-set! self y (+ b (ivar-ref self y)))) ;; more wordy
(+ ID ((initWithX: DBL a) (Y: DBL b))
(let ((p @[ @[MyPoint alloc] init]))
@[p moveByX: a Y: b]
p)))
#;1> @[MyPoint initWithX: 3.4 Y: 4.5]
MyPoint init
#<objc-instance <MyPoint: (3.4, 4.5)>>If #f, an error will occur when attempting to redefine an existing class with define-objc-class.
If #t, redefinition is allowed and a warning will be printed.
Types
Objective C is a typed language, and the bridge uses these types to decide how to pass values into and out of Objective C. Each type is represented by a specific string and the bridge provides a variable containing each type string. The variable names and their associated Objective C types are listed below.
Note: define-objc-class and define-method expect short typenames, without the objc: prefix. For example, use type DBL instead of objc:DBL. The full names are used for lower-level methods such as objc:add-method and objc:set-ivars.
| objc:ID | id |
| objc:CLASS | Class |
| objc:SEL | SEL |
| objc:INT | int |
| objc:DBL | double |
| objc:FLT | float |
| objc:CHR | char |
| objc:SHT | short |
| objc:LNG | long |
| objc:USHT | unsigned short |
| objc:UINT | unsigned int |
| objc:UCHR | unsigned char |
| objc:ULNG | unsigned long |
| objc:BOOL | BOOL |
| objc:PTR | void * |
| objc:CHARPTR | char * |
| objc:VOID | void |
Numeric types are converted to and from Scheme numbers just as in Chicken's C FFI. id and Class types are wrapped and unwrapped in objc:instance and objc:class types.
Scheme strings are converted to NSStrings when passed to Objective C, but NSStrings are kept as objc:instance objects when passed to Scheme. Use (objc:nsstring->string s) to convert to a Scheme string.
BOOL and CHR are actually identical types and cannot be distinguished. For this reason, (char)0 becomes #f when passed to Scheme, and #t and #f become (char)1 and (char)0 when passed to Objective C. This allows Scheme predicates to work correctly. Other character values are passed through transparently, so character passing works in nearly all cases. Note that UCHR values do not have special-case transformations, as UCHR values are never boolean.
Selectors are converted to strings when passed to Scheme, and strings converted back to selectors when passed to Objective C. Note that selectors may be wrapped in objc:selector objects in the future.
CHARPTR (char *) types are converted to Scheme strings, but conversion to CHARPTR is disabled.
Struct, union, and array types cannot currently be sent to or received from Objective C.
Memory management
The bridge strives to handle memory management automatically. In general terms, this is accomplished by implicitly retaining an instance object when it is passed into Scheme, and releasing it when the objc:instance is finalized. The bridge knows that certain selectors, such as alloc and copy, by convention donate a retain reference to you, and adjusts its retain count accordingly. Furthermore, passing an objc:instance into Objective C retains and autoreleases that object, which is necessary to ensure that short-lived objects (such as automatically created strings) remain valid until the end of a method invocation. (Each invocation is wrapped in an autorelease pool, hence the autorelease.)
In general, this means you don't have to worry about releasing, autoreleasing or retaining objects. The expression (let ((m @[MyPoint alloc])) (void)), for example, incurs no memory penalty as m is garbage collected like any other Scheme object. This principle extends to NSStrings that are created by the bridge when converted from Scheme strings. Additionally, you may return newly allocated objects from Scheme classes without autoreleasing them.
However, there are some limitations. Overriding memory-management selectors such as alloc, release, and dealloc is not supported (although alloc does appear to work fine, caveat emptor). Sending an autorelease message has no effect due to the current implementation of method invocation. Finally, although the author has tried to ensure automatic memory management works as advertised, certain cases (especially involving calls from Objective C to Scheme) have not been tested and may be problematic at this point.
Lowlevel
Registers CLASSNAME (a string) having superclass SUPERCLASS (an objc:class) with the Objective C runtime. An error is raised if CLASSNAME already exists.
Defines in CLASS (an objc:class) the instance variables in IVARS (a list of objc:instance-var records). The offset parameter of the instance variable records is ignored.
Warning: all old instance variables in MyClass will be removed first. Also, we don't check for conflicts with superclass instance variables. This should be remedied in a future release.
Example:
(objc:set-ivars MyClass (list (make-objc:instance-var "jimmy" objc:INT 0)
(make-objc:instance-var "cammy" objc:DBL 0)Adds a class or instance method to CLASS.
| METHOD |
Method name as a string (e.g.
"setWidth:height:") |
| TYPES |
List of encoded argument type strings (such as
objc:INT or "@"). |
| PROC | Scheme procedure representing the method. |
The structure of the TYPES list is (RETURN-TYPE SELF SELECTOR METHOD-ARGS...).
Transformation:
(objc:define-method MyClass DBL ((sel1: INT i) (sel2: DBL d))
(print i) (+ i d))
=>
(objc:add-method MyClass "sel1:sel2:" (list objc:DBL objc:ID objc:SEL objc:INT objc:DBL)
(lambda (self sel i d) (print i) (+ i d)))
Returned by objc:class-ivar-list, and used by objc:set-ivars.
| name | Name as a string. |
| type | Type as an encoded type string. |
| offset | Offset within class -- for debugging only. |
Creates an autorelease pool that lasts for the duration of the thunk.
A global autorelease pool is created automatically at startup, one is wrapped around the main Application Kit event loop, one is wrapped around every call to Objective C, and memory management is generally otherwise automatic. It is considered unlikely you will have to use this, unless you send Objective C messages directly inside a foreign-lambda.
Import every class visible to the runtime, as if define-objc-classes had been run on all available classes. Useful for debugging. Note that some (rare) classes are not derived from NSObject, and will not respond to standard NSObject selectors, may throw exceptions, or may crash if used.
Looks up and returns a list of all available classes. At startup, the result of this call is stored in the variable objc:classes.
It is possible to create Cocoa applications using this extension, but the documentation is still pending. For now, a working application is included in this egg. Untar the egg, change to the tests/ directory, and type make. An application called Temperature Converter will be built.
Copyright (c) 2005, J. Zbigniew Szadkowski. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.