Skip to content

apr3vau/objc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Objective-C to Lisp Binding with Transparent Layer

Dependencies:

(ql:quickload '(:alexandria :anaphora :closer-mop :cffi :cffi-libffi))

Packages:

OBJC
Main Package
OBJC-CLASS
For Class Definitions
OBJC-META
For Metaclass Definitions
OBJC-METHOD
For Obj-C -> Lisp Generic Function Methods
OBJC-PROP
Obj-C Properties -> Lisp Slot Names

The source code is separated using titles and #\Page, please use C-x [ and C-x ] to navigate throught subtitles.

Usage

To get a Obj-C class, either pass its string name or the Lisp name it should be translated to cls macro or ensure-objc-class function, or use string name for objc-lookup-class:

(objc:cls ns-object)
or
(objc:ensure-objc-class 'objc-class::ns-object)
(objc:ensure-objc-class "NSObject")
or
(objc:objc-lookup-class "NSObject")

;; => #<OBJC-META:NS-OBJECT OBJC-CLASS:NS-OBJECT>

(These are convenient functions, CLOS & MOP methods will be introduced below.)

The class object will be automatically created inside corresponding (OBJC-CLASS or OBJC-META) package, with all superclasses & metaclasses defined. By default, all methods under the class will also be registered in OBJC-METHOD package, and class properties will be registered as Lisp class slots named in OBJC-PROP package.

  #<OBJC-META:NS-OBJECT {7005C64A43}>
--------------------
Name: OBJC-CLASS:NS-OBJECT
Super classes: #<STANDARD-CLASS OBJC::OBJC-OBJECT>
Direct Slots: CLASS-DESCRIPTION, ATTRIBUTE-KEYS, TO-ONE-RELATIONSHIP-KEYS, TO-MANY-RELATIONSHIP-KEYS, OBSERVATION-INFO, CLASS-FOR-KEYED-ARCHIVER, AUTO-CONTENT-ACCESSING-PROXY, SCRIPTING-PROPERTIES, CLASS-CODE, CLASS-NAME, EXPOSED-BINDINGS, _NS_OBSERVATION-TRACKING-DICTIONARY, HASH, SUPERCLASS, DESCRIPTION, DEBUG-DESCRIPTION, HASH, SUPERCLASS, DESCRIPTION, DEBUG-DESCRIPTION, _AX-IS-WRAPPED-POINTER, ACCESSIBILITY-SWIFT-UI-DEFAULT-ACTION-STORED-BLOCK, ACCESSIBILITY-SWIFT-UI-STORED-LINK-ROTOR, SWIFTUI_ACCESSIBILITY-LABEL, KNOWN-REPRESENTED-ELEMENT, ROTOR-OWNER-ELEMENT, HASH, SUPERCLASS, DESCRIPTION, DEBUG-DESCRIPTION
Effective Slots: #<N/A (class not finalized)> [finalize]
Sub classes: NS-RULER-MARKER, NS-GRID-ROW, NS-GRID-COLUMN, NS-GRID-CELL, NS-CELL, NS-FILE-PROMISE-RECEIVER, NS-FILE-PROMISE-PROVIDER, NS-CONTROLLER, NS-DOCUMENT-CONTROLLER, NS-DOCUMENT, NS-PASTEBOARD-ITEM, NS-PASTEBOARD, NS-WORKSPACE, NS-RESPONDER, NS-DICTIONARY, NS-SET, NS-ARRAY, NS-STRING, NS-VALUE, PROTOCOL
Precedence List: #<N/A (class not finalized)>
Prototype: #<N/A (class not finalized)>
--------------------
 Group slots by inheritance [X]
 Sort slots alphabetically  [X]

CLASS:
[ ]  %DOCUMENTATION                     = NIL
[ ]  CLASS-EQ-SPECIALIZER               = #<SB-PCL::CLASS-EQ-SPECIALIZER #<OBJC-META:NS-OBJECT OBJC-CLASS:NS-OBJECT>>
[ ]  DIRECT-METHODS                     = (NIL)
[ ]  DIRECT-SUBCLASSES                  = (#<OBJC-META:NS-RULER-MARKER OBJC-CLASS:NS-RULER-MARKER> #<OBJC-META:NS-GRID-ROW OBJC-CLASS:NS-GRID-ROW> #<OBJC-META:NS-GRID-COLUMN OBJC-CLASS:NS-GRID-COLUMN> #<OBJC-META:NS-GRID-CELL OBJC-CLASS:NS-GRID-CELL> #<OBJC-META:NS-CELL OBJC-CLASS:NS-CELL> #<OBJC-META:NS-FILE-PROMISE-RECEIVER OBJC-CLASS:NS-FILE-PROMISE-RECEIVER> #<OBJC-META:NS-FILE-PROMISE-PROVIDER OBJC-CLASS:NS-FILE-PROMISE-PROVIDER> #<OBJC-META:NS-CONTROLLER OBJC-CLASS:NS-CONTROLLER> ..)
[ ]  DIRECT-SUPERCLASSES                = (#<STANDARD-CLASS OBJC::OBJC-OBJECT>)
[ ]  FINALIZED-P                        = NIL
[ ]  NAME                               = OBJC-CLASS:NS-OBJECT
[ ]  SAFE-P                             = NIL

DEFINITION-SOURCE-MIXIN:
[ ]  SOURCE                             = #S(SB-C:DEFINITION-SOURCE-LOCATION :NAMESTRING "/Users/april/common-lisp/objc/objc.lisp" :INDICES 4521988)

NS-OBJECT:
[ ]  ACCESS-INSTANCE-VARIABLES-DIRECTLY = T

OBJC-CLASS:
[ ]  AUTO-BIND-PROPERTIES               = T
[ ]  AUTO-REGISTER-METHODS              = T
[ ]  OBJC-CLASS-NAME                    = "NSObject"

OBJC-OBJECT:
[ ]  OBJ                                = #.(SB-SYS:INT-SAP #X1F2689D70)

PCL-CLASS:
[ ]  %CLASS-PRECEDENCE-LIST             = #<unbound>
[ ]  CAN-PRECEDE-LIST                   = (#<SB-PCL:SYSTEM-CLASS COMMON-LISP:T> #<SB-PCL::SLOT-CLASS SB-PCL::SLOT-OBJECT> #<STANDARD-CLASS COMMON-LISP:STANDARD-OBJECT> #<STANDARD-CLASS OBJC::OBJC-OBJECT>)
[ ]  CPL-AVAILABLE-P                    = NIL
[ ]  INCOMPATIBLE-SUPERCLASS-LIST       = NIL
[ ]  PROTOTYPE                          = NIL
[ ]  WRAPPER                            = #<SB-KERNEL:LAYOUT for OBJC-CLASS:NS-OBJECT {7005241303}>

PLIST-MIXIN:
[ ]  PLIST                              = NIL

SLOT-CLASS:
[ ]  DIRECT-SLOTS                       = (#<OBJC::OBJC-PROPERTY-SLOT OBJC-PROP:CLASS-DESCRIPTION> #<OBJC::OBJC-PROPERTY-SLOT OBJC-PROP:ATTRIBUTE-KEYS> #<OBJC::OBJC-PROPERTY-SLOT OBJC-PROP:TO-ONE-RELATIONSHIP-KEYS> #<OBJC::OBJC-PROPERTY-SLOT OBJC-PROP:TO-MANY-RELATIONSHIP-KEYS> #<OBJC::OBJC-PROPERTY-SLOT OBJC-PROP:OBSERVATION-INFO> #<OBJC::OBJC-PROPERTY-SLOT OBJC-PROP:CLASS-FOR-KEYED-ARCHIVER> #<OBJC::OBJC-PROPERTY-SLOT OBJC-PROP:AUTO-CONTENT-ACCESSING-PROXY> #<OBJC::OBJC-PROPERTY-SLOT OBJC-PROP:SCRIPTING-PROPERTIES> ..)
[ ]  SLOTS                              = NIL

SPECIALIZER:
[ ]  %TYPE                              = (CLASS #<OBJC-META:NS-OBJECT OBJC-CLASS:NS-OBJECT>)

[set value]  [make unbound]

To control the behaviour, you can use the MOP function ensure-class, or even defclass directly.

(c2mop:ensure-class 'objc-class:ns-object
                    :metaclass 'objc:objc-class
                    :auto-bind-properties nil
                    :auto-register-methods nil)
or
(defclass objc-class:ns-object () ()
  (:metaclass objc-class))

FIXME: Currently we didn’t implemented change-class relative methods on objc-class, so all class can only be defined once. Execution of the form above will signal error because NSObject has been defined. It’s just demonstrating purpose.

To make an instance:

(make-instance (cls ns-object))

Note that this is using class_createInstance runtime function, you may need to do additional initialization for the object.

or if you has the object’s Obj-C pointer:

(make-instance (cls ns-object) :objc-object <pointer>)

To call a method:

(objc-method:new (objc:cls ns-object))
or
(funcall (objc:sel new) (objc:cls ns-object))

;; => #<OBJC-CLASS:NS-OBJECT {700964F153}>

Use slot-value to get the Obj-C property:

(slot-value (objc-method:new (objc::cls ns-object)) 'objc-prop:hash)
;; => 105553174675536 (47 bits, #x6000037B4050)

Source Explaination

The objc-raw.lisp are raw CFFI bindings for Obj-C runtime functions. All symbols are internal, and function argument are referenced by pointer. It’s for utility purpose.


The first page of objc.lisp is the Name Translator. It defines methods on cffi:translate-name-from-foreign and cffi:translate-name-to-foreign to makes it suitable for converting Obj-C names:

  • Special words (“NS”, “UTF”, “URL”, etc.) are specially marked out;
  • For Class and Metaclass names the translation should be initial-uppered;
  • For selector, : will be converted to ., for Lisp compatibility.

These functions are specialized to OBJC* packages.

Example:

(cffi:translate-name-to-foreign name (find-package "OBJC-PROP"))

The second page is about Obj-C Type Encodings. We provide:

  • parse-objc-type-encoding-to-lisp
  • parse-objc-type-encoding-to-c
  • parse-c-type-to-objc-encoding
  • parse-lisp-type-to-c
  • parse-lisp-type-to-objc-encoding

The third page is about objc-object and selector.

All Obj-C object pointer will be wrapped into an objc-object, which has a slot OBJC:OBJ for the wrapped pointer.

FIXME: Some Obj-C objects are not presented in pointer, like NSRange. For NSRange I’ve written a wrapper alone, but I’m not prepared to handle this problem systematically…

selector is an instance of funcallable-standard-class metaclass. it can be funcalled to invoke the method, just like regular Obj-C message sending.

selector is also a CFFI foreign type, which will automatically parse selector typed argument to the instance of selector.


The fourth page is about Obj-C property to Lisp class slot definition converter.

This page only contains slot definition metaobject definition, real converting method is two page after, as compute-effective-slot-definition method. That’s because the method must be defined after objc-class has been defined.


The fifth page is about Obj-C class foreign-type parser.


The sixth page contains the definition of obj-c class in Lisp: objc-class and objc-metaclass. It’s also contains method of compute-effective-slot-definition, slot-value-using-class, (setf slot-value-using-class)


The seventh page is Obj-C class => Lisp class converter, mainly ensure-class-using-class method. It will convert any class definition to Obj-C class (either regestering or defining), if it has objc-class as :metaobject

About

Objective-C to Lisp Binding with Transparent Layer

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published