Skip to content

objc #

This vlang package provides Objective-C Runtime bindings for V.

Status

It is currently working in progress and should be considered experimental. It's only tested on x86_64 architecture, macOS Sonoma 14.0.

Supported features:

  • Bool type
  • Id type
  • Load classes
  • Create instances
  • Register selectors
  • Send messages (varargs are not supported)
  • Class declaration

Installation

v install magic003.objc

Usage

Bool type

The Bool type is an alias of the V bool type.

assert objc.yes == true
assert objc.no == false

Load a class

An Objective-C class can be loaded using either a factory function or a static type method.

cls1 := objc.Class.get('NSMutableArray') or { panic('failed to load class NSMutableArray') }
cls2 := objc.class('NSMutableArray') or { panic('failed to load class NSMutableArray') }

Register and get a selector

An Objective-C selector can be registered using either a factory function or a static type method.

s1 := objc.Sel.get('init')
s2 := objc.sel('init')

Send messages

Messages can be sent to a class or an instance. There are two types of messages:

  • request[R](): a message with return type R.
  • notify(): a message without a return value.
unsafe {
    // a mutable array instance is created via chained messages
    arr := cls1.message(objc.sel('alloc')).request[objc.Id]()
            .message(objc.sel('init')).request[objc.Id]()

    // load the NSObject class and create an instance
    obj_cls := objc.class('NSObject') or { panic('failed to load class NSObject') }
    obj := obj_cls.message(sel('new')).request[objc.Id]()

    // add an object to the array. Message with one argument and no return value. 
    // Use `args2()`, `args3()` and etc for more arguments.
    arr.message(sel('addObject:')).args1(obj).notify()

    // message without an argument.
    size := arr.message(sel('count')).request[u64]()
    assert size == 1
}

Declare a new class

New classes can be declared and registered with the Objective-C Runtime.

superclass := objc.class('NSObject') or { panic('failed to load class NSObject') }
// create a new class with `NSObject` as the super class.
decl := ClassDecl.new(superclass, 'NewClass', 0) or {
    panic('failed to create class NewClass')
}

// add ivars
decl.add_ivar[i64]('num')
decl.add_ivar[objc.Id]('obj')

// add methods
m1 := objc.void_method_1[bool](fn (self objc.Id, cmd objc.Sel, flag bool) {
    // do something
})
unsafe { decl.add_method(objc.sel('method1:'), m1) }
m2: = objc.method_1[int, objc.Id](fn (self objc.Id, cmd objc.Sel, obj objc.Id) int {
    return 10
})
unsafe { delc.add_method(objc.sel('method2:'), m2) }

// register the class
cls := decl.register()

unsafe {
    // create an instance from the new class
    obj := cls.message(objc.sel('new')).request[objc.Id]()
    
    // set ivar
    obj.set_ivar('num', 1)

    // call method
    obj.message(objc.sel('method1:')).args1(true).notify()
}

Examples

The unit tests have basic usages.

Check out the examples folder for more examples.

Documentation

References

Constants #

const yes = Bool(true)

yes as true.

const no = Bool(false)

no as false.

fn class #

fn class(name string) ?Class

class returns the class definition of a specified class. It returns none if the class is not registered with the Objective-C runtime.

Example

cls := class('NSObject') or { panic('failed to load class NSObject') }

fn void_method_4 #

fn void_method_4[A, B, D, E](imp fn (self Id, cmd Sel, a A, b B, d D, e E)) MethodImpl

void_method_4 creates a MethodImpl which has four arguments and no return value.

fn encode #

fn encode[T]() !ec.Encoding

encode returns the Objective-C encoding of the type parameter T.

fn method_0 #

fn method_0[R](imp fn (self Id, cmd Sel) R) MethodImpl

method_0 creates a MethodImpl which returns a value and doesn't have an argument.

fn method_1 #

fn method_1[R, A](imp fn (self Id, cmd Sel, a A) R) MethodImpl

method_1 creates a MethodImpl which has one argument and returns a value.

fn method_2 #

fn method_2[R, A, B](imp fn (self Id, cmd Sel, a A, b B) R) MethodImpl

method_2 creates a MethodImpl which has two arguments and returns a value.

fn method_3 #

fn method_3[R, A, B, D](imp fn (self Id, cmd Sel, a A, b B, d D) R) MethodImpl

method_3 creates a MethodImpl which has three arguments and returns a value.

fn method_4 #

fn method_4[R, A, B, D, E](imp fn (self Id, cmd Sel, a A, b B, d D, e E) R) MethodImpl

method_4 creates a MethodImpl which has four arguments and returns a value.

fn sel #

fn sel(name string) Sel

sel registers a method with the Objective-C runtime system, maps the method name to a selector, and returns the selector value.

Example

sel1 := sel('new')
sel2 := sel('allocWithZone:')

fn void_method_0 #

fn void_method_0(imp fn (self Id, cmd Sel)) MethodImpl

void_method_0 creates a MethodImpl which doesn't have an argument and return value.

fn void_method_1 #

fn void_method_1[A](imp fn (self Id, cmd Sel, a A)) MethodImpl

void_method_1 creates a MethodImpl which has one argument and no return value.

fn void_method_2 #

fn void_method_2[A, B](imp fn (self Id, cmd Sel, a A, b B)) MethodImpl

void_method_2 creates a MethodImpl which has two arguments and no return value.

fn void_method_3 #

fn void_method_3[A, B, D](imp fn (self Id, cmd Sel, a A, b B, d D)) MethodImpl

void_method_3 creates a MethodImpl which has three arguments and no return value.

interface MethodImpl #

interface MethodImpl {
	// the function implementation.
	imp Imp
	// encodings returns the encodings of the method.
	encodings() []ec.Encoding
}

An interface of the method implementation which can be added to a class declaration.

fn (Msg1[A]) request #

unsafe
fn (m Msg1[A]) request[R]() R

request sends a message requesting for a value of type R.
Unsafe because the caller must ensure the return type R and argument types match those of the Objective-C function.

fn (Msg1[A]) notify #

unsafe
fn (m Msg1[A]) notify()

notify sends a message without a return value.
Unsafe because the caller must ensure the argument types match those of the Objective-C function.

type Bool #

type Bool = bool

A type that represents a Boolean value in Objective-C.

fn (Msg4[A, B, D, E]) request #

unsafe
fn (m Msg4[A, B, D, E]) request[R]() R

request sends a message requesting for a value of type R.
Unsafe because the caller must ensure the return type R and argument types match those of the Objective-C function.

fn (Msg4[A, B, D, E]) notify #

unsafe
fn (m Msg4[A, B, D, E]) notify()

notify sends a message without a return value.
Unsafe because the caller must ensure the argument types match those of the Objective-C function.

fn (MsgBuilder) args1 #

fn (m MsgBuilder) args1[A](a A) Msg1[A]

args1 adds 1 argument to the message.

fn (MsgBuilder) args2 #

fn (m MsgBuilder) args2[A, B](a A, b B) Msg2[A, B]

args2 adds 2 arguments to the message.

fn (MsgBuilder) args3 #

fn (m MsgBuilder) args3[A, B, D](a A, b B, d D) Msg3[A, B, D]

args3 adds 3 arguments to the message.

fn (MsgBuilder) args4 #

fn (m MsgBuilder) args4[A, B, D, E](a A, b B, d D, e E) Msg4[A, B, D, E]

args4 adds 4 arguments to the message.

fn (MsgBuilder) request #

unsafe
fn (m MsgBuilder) request[R]() R

request sends a message requesting a value of type R.
Unsafe because the caller must ensure the return type R matches that of the Objective-C function.

fn (MsgBuilder) notify #

unsafe
fn (m MsgBuilder) notify()

notify sends a message without a return value.
Unsafe because the caller must ensure the argument types match those of the Objective-C function.

type Sel #

type Sel = voidptr

A type that represents a method selector, SEL, in Objective-C.

fn (Sel) Sel__static__get #

fn Sel.get(name string) Sel

Sel.get registers a method with the Objective-C runtime system, maps the method name to a selector, and returns the selector value.

Example

sel1 := Sel.get('new')
sel2 := Sel.get('allocWithZone:')

fn (Msg2[A, B]) request #

unsafe
fn (m Msg2[A, B]) request[R]() R

request sends a message requesting for a value of type R.
Unsafe because the caller must ensure the return type R and argument types match those of the Objective-C function.

fn (Msg2[A, B]) notify #

unsafe
fn (m Msg2[A, B]) notify()

notify sends a message without a return value.
Unsafe because the caller must ensure the argument types match those of the Objective-C function.

fn (Id) message #

fn (id Id) message(op Sel) MsgBuilder

message creates a message with the id as the receiver and op as the method selector.

fn (Id) class #

fn (id Id) class() Class

class returns the class of this instance.

fn (Id) set_ivar #

unsafe
fn (id Id) set_ivar[T](name string, value T)

set_ivar sets the value of an instance variable.
Unsafe because the caller must ensure the ivar is actually of type T.

fn (Id) get_ivar #

unsafe
fn (id Id) get_ivar[T](name string) T

set_ivar returns the value of an instance variable.
Unsafe because the caller must ensure the ivar is actually of type T.

type Imp #

type Imp = fn ()

A pointer to the start of a method implementation.

fn (Msg3[A, B, D]) request #

unsafe
fn (m Msg3[A, B, D]) request[R]() R

request sends a message requesting for a value of type R.
Unsafe because the caller must ensure the return type R and argument types match those of the Objective-C function.

fn (Msg3[A, B, D]) notify #

unsafe
fn (m Msg3[A, B, D]) notify()

notify sends a message without a return value.
Unsafe because the caller must ensure the argument types match those of the Objective-C function.

struct Class #

struct Class {
	ptr voidptr [required] // the Objective-C Class object
}

A type that represents an Objective-C class.

fn (Class) Class__static__get #

fn Class.get(name string) ?Class

Class.get returns the class definition of a specified class. It returns none if the class is not registered with the Objective-C runtime.

fn (Class) message #

fn (c Class) message(op Sel) MsgBuilder

message creates a message with the class instance as the receiver and op as the method selector.

fn (Class) instance_variable #

fn (c Class) instance_variable(name string) ?Ivar

instance_variable returns the Ivar for a specified instance variable of a given class.

struct ClassDecl #

struct ClassDecl {
	cls voidptr [required] // the Objective-C Class object
}

A type used to declare a new class.

fn (ClassDecl) ClassDecl__static__new #

fn ClassDecl.new(superclass Class, name string, extra_bytes usize) ?ClassDecl

ClassDecl.new creates a new class. It returns none if the class could not be created (for example, the desired name is already in use).

fn (ClassDecl) add_ivar #

fn (d ClassDecl) add_ivar[T](name string) bool

add_ivar adds a new instance variable of type T to a class.

fn (ClassDecl) add_method #

unsafe
fn (d ClassDecl) add_method(name Sel, method MethodImpl) bool

add_method adds a new method to a class.
Unsafe because the caller must ensure the method type matches that is expected by Objective-C.

fn (ClassDecl) register #

fn (d ClassDecl) register() Class

register registers the class.

struct Ivar #

struct Ivar {
	ptr voidptr [required]
}

A type that represents an instance variable in an Objective-C class.

fn (Ivar) name #

fn (v Ivar) name() string

name returns the name of an instance variable.

fn (Ivar) type_encoding #

fn (v Ivar) type_encoding() string

type_encoding returns the type string of an instance variable.

fn (Ivar) offset #

fn (v Ivar) offset() isize

offset returns the offset of an instance variable.