Documentation
¶
Overview ¶
Package objc is a low-level pure Go objective-c runtime. This package is easy to use incorrectly, so it is best to use a wrapper that provides the functionality you need in a safer way.
Index ¶
- func InvokeBlock[T any](block Block, args ...any) (result T, err error)
- func Send[T any](id ID, sel SEL, args ...any) T
- func SendSuper[T any](id ID, sel SEL, args ...any) T
- type Block
- type Class
- type FieldDef
- type ID
- type IMP
- type Ivar
- type IvarAttrib
- type MethodDef
- type MethodDescription
- type Property
- type PropertyAttribute
- type Protocol
- func (p *Protocol) AddMethodDescription(name SEL, types string, isRequiredMethod, isInstanceMethod bool)
- func (p *Protocol) AddProperty(name string, attributes []PropertyAttribute, ...)
- func (p *Protocol) AddProtocol(protocol *Protocol)
- func (p *Protocol) CopyMethodDescriptionList(isRequiredMethod, isInstanceMethod bool) []MethodDescription
- func (p *Protocol) CopyPropertyList(isRequiredProperty, isInstanceProperty bool) []Property
- func (p *Protocol) CopyProtocolList() []*Protocol
- func (p *Protocol) Equals(p2 *Protocol) bool
- func (p *Protocol) Name() string
- func (p *Protocol) Register()
- type SEL
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func InvokeBlock ¶ added in v0.9.0
InvokeBlock is a convenience method for calling the implementation of a block. The block implementation must return 1 value.
Example ¶
package main import ( "fmt" "github.com/ebitengine/purego/objc" ) func main() { type vector struct { X, Y, Z float64 } block := objc.NewBlock( func(block objc.Block, v1, v2 *vector) *vector { return &vector{ X: v1.Y*v2.Z - v1.Z*v2.Y, Y: v1.Z*v2.X - v1.X*v2.Z, Z: v1.X*v2.Y - v1.Y*v2.X, } }, ) defer block.Release() result, err := objc.InvokeBlock[*vector]( block, &vector{X: 0.1, Y: 2.3, Z: 4.5}, &vector{X: 6.7, Y: 8.9, Z: 0.1}, ) fmt.Println(*result, err) }
Output: {-39.82 30.14 -14.52} <nil>
func Send ¶ added in v0.2.0
Send is a convenience method for sending messages to objects that can return any type. This function takes a SEL instead of a string since RegisterName grabs the global Objective-C lock. It is best to cache the result of RegisterName.
Example ¶
package main import ( "fmt" "github.com/ebitengine/purego/objc" ) func main() { type NSRange struct { Location, Range uint } class_NSString := objc.GetClass("NSString") sel_stringWithUTF8String := objc.RegisterName("stringWithUTF8String:") fullString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "Hello, World!\x00") subString := objc.ID(class_NSString).Send(sel_stringWithUTF8String, "lo, Wor\x00") r := objc.Send[NSRange](fullString, objc.RegisterName("rangeOfString:"), subString) fmt.Println(r) }
Output: {3 7}
func SendSuper ¶ added in v0.2.0
SendSuper is a convenience method for sending message to object's super that can return any type. This function takes a SEL instead of a string since RegisterName grabs the global Objective-C lock. It is best to cache the result of RegisterName.
Example ¶
package main import ( "fmt" "github.com/ebitengine/purego/objc" ) func main() { super, err := objc.RegisterClass( "SuperObject2", objc.GetClass("NSObject"), nil, nil, []objc.MethodDef{ { Cmd: objc.RegisterName("doSomething"), Fn: func(self objc.ID, _cmd objc.SEL) int { return 16 }, }, }, ) if err != nil { panic(err) } child, err := objc.RegisterClass( "ChildObject2", super, nil, nil, []objc.MethodDef{ { Cmd: objc.RegisterName("doSomething"), Fn: func(self objc.ID, _cmd objc.SEL) int { return 24 }, }, }, ) if err != nil { panic(err) } res := objc.SendSuper[int](objc.ID(child).Send(objc.RegisterName("new")), objc.RegisterName("doSomething")) fmt.Println(res) }
Output: 16
Types ¶
type Block ¶ added in v0.9.0
type Block ID
Block is an opaque pointer to an Objective-C object containing a function with its associated closure.
func NewBlock ¶ added in v0.9.0
NewBlock takes a Go function that takes a Block as its first argument. It returns an Block that can be called by Objective-C code. The function panics if an error occurs. Use Block.Release to free this block when it is no longer in use.
Example ¶
package main import ( "fmt" "github.com/ebitengine/purego" "github.com/ebitengine/purego/objc" ) func main() { _, err := purego.Dlopen("/System/Library/Frameworks/Foundation.framework/Foundation", purego.RTLD_GLOBAL|purego.RTLD_NOW) if err != nil { panic(err) } var count = 0 block := objc.NewBlock( func(block objc.Block, line objc.ID, stop *bool) { count++ fmt.Printf("LINE %d: %s\n", count, objc.Send[string](line, objc.RegisterName("UTF8String"))) *stop = count == 3 }, ) defer block.Release() lines := objc.ID(objc.GetClass("NSString")).Send(objc.RegisterName("stringWithUTF8String:"), "Alpha\nBeta\nGamma\nDelta\nEpsilon") defer lines.Send(objc.RegisterName("release")) lines.Send(objc.RegisterName("enumerateLinesUsingBlock:"), block) }
Output: LINE 1: Alpha LINE 2: Beta LINE 3: Gamma
func (Block) Copy ¶ added in v0.9.0
Copy creates a copy of a block on the Objective-C heap (or increments the reference count if already on the heap). Use Block.Release to free the copy when it is no longer in use.
type Class ¶
type Class uintptr
Class is an opaque type that represents an Objective-C class.
func GetClass ¶
GetClass returns the Class object for the named class, or nil if the class is not registered with the Objective-C runtime.
func RegisterClass ¶ added in v0.2.0
func RegisterClass(name string, superClass Class, protocols []*Protocol, ivars []FieldDef, methods []MethodDef) (Class, error)
RegisterClass takes the name of the class to create, the superclass, a list of protocols this class implements, a list of fields this class has and a list of methods. It returns the created class or an error describing what went wrong.
Example ¶
package main import ( "fmt" "reflect" "github.com/ebitengine/purego/objc" ) func main() { var ( sel_new = objc.RegisterName("new") sel_init = objc.RegisterName("init") sel_setBar = objc.RegisterName("setBar:") sel_bar = objc.RegisterName("bar") BarInit = func(id objc.ID, cmd objc.SEL) objc.ID { return id.SendSuper(cmd) } ) class, err := objc.RegisterClass( "BarObject", objc.GetClass("NSObject"), []*objc.Protocol{ objc.GetProtocol("NSDelegateWindow"), }, []objc.FieldDef{ { Name: "bar", Type: reflect.TypeOf(int(0)), Attribute: objc.ReadWrite, }, { Name: "foo", Type: reflect.TypeOf(false), Attribute: objc.ReadWrite, }, }, []objc.MethodDef{ { Cmd: sel_init, Fn: BarInit, }, }, ) if err != nil { panic(err) } object := objc.ID(class).Send(sel_new) object.Send(sel_setBar, 123) bar := int(object.Send(sel_bar)) fmt.Println(bar) }
Output: 123
Example (Helloworld) ¶
package main import ( "fmt" "github.com/ebitengine/purego/objc" ) func main() { class, err := objc.RegisterClass( "FooObject", objc.GetClass("NSObject"), nil, nil, []objc.MethodDef{ { Cmd: objc.RegisterName("run"), Fn: func(self objc.ID, _cmd objc.SEL) { fmt.Println("Hello World!") }, }, }, ) if err != nil { panic(err) } object := objc.ID(class).Send(objc.RegisterName("new")) object.Send(objc.RegisterName("run")) }
Output: Hello World!
func (Class) AddMethod ¶
AddMethod adds a new method to a class with a given name and implementation. The types argument is a string containing the mapping of parameters and return type. Since the function must take at least two arguments—self and _cmd, the second and third characters must be “@:” (the first character is the return type).
func (Class) AddProtocol ¶ added in v0.2.0
AddProtocol adds a protocol to a class. Returns true if the protocol was added successfully, otherwise false (for example, the class already conforms to that protocol).
func (Class) InstanceSize ¶ added in v0.2.0
InstanceSize returns the size in bytes of instances of the class or 0 if cls is nil
func (Class) InstanceVariable ¶
InstanceVariable returns an Ivar data structure containing information about the instance variable specified by name.
func (Class) SuperClass ¶
SuperClass returns the superclass of a class. You should usually use NSObject‘s superclass method instead of this function.
type FieldDef ¶ added in v0.5.0
type FieldDef struct { Name string Type reflect.Type Attribute IvarAttrib }
FieldDef is a definition of a field to add to an Objective-C class. The name of the field is what will be used to access it through the Ivar. If the type is bool the name cannot start with `is` since a getter will be generated with the name `isBoolName`. The name also cannot contain any spaces. The type is the Go equivalent type of the Ivar. Attribute determines if a getter and or setter method is generated for this field.
type ID ¶
type ID uintptr
ID is an opaque pointer to some Objective-C object
func (ID) Send ¶
Send is a convenience method for sending messages to objects. This function takes a SEL instead of a string since RegisterName grabs the global Objective-C lock. It is best to cache the result of RegisterName.
func (ID) SendSuper ¶
SendSuper is a convenience method for sending message to object's super. This function takes a SEL instead of a string since RegisterName grabs the global Objective-C lock. It is best to cache the result of RegisterName.
Example ¶
package main import ( "fmt" "github.com/ebitengine/purego/objc" ) func main() { super, err := objc.RegisterClass( "SuperObject", objc.GetClass("NSObject"), nil, nil, []objc.MethodDef{ { Cmd: objc.RegisterName("doSomething"), Fn: func(self objc.ID, _cmd objc.SEL) { fmt.Println("In Super!") }, }, }, ) if err != nil { panic(err) } child, err := objc.RegisterClass( "ChildObject", super, nil, nil, []objc.MethodDef{ { Cmd: objc.RegisterName("doSomething"), Fn: func(self objc.ID, _cmd objc.SEL) { fmt.Println("In Child") self.SendSuper(_cmd) }, }, }, ) if err != nil { panic(err) } objc.ID(child).Send(objc.RegisterName("new")).Send(objc.RegisterName("doSomething")) }
Output: In Child In Super!
type IMP ¶
type IMP uintptr
IMP is a function pointer that can be called by Objective-C code.
Example ¶
package main import ( "fmt" "github.com/ebitengine/purego" "github.com/ebitengine/purego/objc" ) func main() { imp := objc.NewIMP(func(self objc.ID, _cmd objc.SEL, a3, a4, a5, a6, a7, a8, a9 int) { fmt.Println("IMP:", self, _cmd, a3, a4, a5, a6, a7, a8, a9) }) purego.SyscallN(uintptr(imp), 105, 567, 9, 2, 3, ^uintptr(4), 4, 8, 9) }
Output: IMP: 105 567 9 2 3 -5 4 8 9
type Ivar ¶
type Ivar uintptr
Ivar an opaque type that represents an instance variable.
type IvarAttrib ¶ added in v0.5.0
type IvarAttrib int
IvarAttrib is the attribute that an ivar has. It affects if and which methods are automatically generated when creating a class with RegisterClass. See Apple Docs for an understanding of these attributes. The fields are still accessible using objc.GetIvar and objc.SetIvar regardless of the value of IvarAttrib.
Take for example this Objective-C code:
@property (readwrite) float value;
In Go, the functions can be accessed as followed:
var value = purego.Send[float32](id, purego.RegisterName("value")) id.Send(purego.RegisterName("setValue:"), 3.46)
const ( ReadOnly IvarAttrib = 1 << iota ReadWrite )
type MethodDef ¶ added in v0.5.0
MethodDef represents the Go function and the selector that ObjC uses to access that function.
type MethodDescription ¶ added in v0.9.0
type MethodDescription struct {
// contains filtered or unexported fields
}
MethodDescription holds the name and type definition of a method.
func (MethodDescription) Name ¶ added in v0.9.0
func (m MethodDescription) Name() string
Name returns the name of this method.
func (MethodDescription) Types ¶ added in v0.9.0
func (m MethodDescription) Types() string
Types returns the OBJC runtime encoded type description.
type Property ¶ added in v0.9.0
type Property uintptr
Property is an opaque type for Objective-C property metadata.
func (Property) Attributes ¶ added in v0.9.0
Attributes returns a comma separated list of PropertyAttribute
type PropertyAttribute ¶ added in v0.9.0
type PropertyAttribute struct {
Name, Value *byte
}
PropertyAttribute contains the null-terminated Name and Value pair of a Properties internal description.
type Protocol ¶ added in v0.2.0
type Protocol [0]func()
Protocol is a type that declares methods that can be implemented by any class.
func AllocateProtocol ¶ added in v0.9.0
AllocateProtocol creates a new protocol in the OBJC runtime or nil if the protocol already exists.
Example ¶
package main import ( "fmt" "log" "github.com/ebitengine/purego/objc" ) func main() { var p *objc.Protocol if p = objc.AllocateProtocol("MyCustomProtocol"); p != nil { p.AddMethodDescription(objc.RegisterName("isFoo"), "B16@0:8", true, true) var adoptedProtocol *objc.Protocol adoptedProtocol = objc.GetProtocol("NSObject") if adoptedProtocol == nil { log.Fatalln("protocol 'NSObject' does not exist") } p.AddProtocol(adoptedProtocol) p.AddProperty("accessibilityElement", []objc.PropertyAttribute{ {Name: &[]byte("T\x00")[0], Value: &[]byte("B\x00")[0]}, {Name: &[]byte("G\x00")[0], Value: &[]byte("isBar\x00")[0]}, }, true, true) p.Register() } p = objc.GetProtocol("MyCustomProtocol") for _, protocol := range p.CopyProtocolList() { fmt.Println(protocol.Name()) } for _, property := range p.CopyPropertyList(true, true) { fmt.Println(property.Name(), property.Attributes()) } for _, method := range p.CopyMethodDescriptionList(true, true) { fmt.Println(method.Name(), method.Types()) } }
Output: NSObject accessibilityElement TB,GisBar isFoo B16@0:8
func GetProtocol ¶ added in v0.2.0
GetProtocol returns the protocol for the given name or nil if there is no protocol by that name.
func (*Protocol) AddMethodDescription ¶ added in v0.9.0
func (p *Protocol) AddMethodDescription(name SEL, types string, isRequiredMethod, isInstanceMethod bool)
AddMethodDescription adds a method to a protocol. This can only be called between AllocateProtocol and Protocol.Register.
func (*Protocol) AddProperty ¶ added in v0.9.0
func (p *Protocol) AddProperty(name string, attributes []PropertyAttribute, isRequiredProperty, isInstanceProperty bool)
AddProperty adds a property to the protocol. This can only be called between AllocateProtocol and Protocol.Register.
func (*Protocol) AddProtocol ¶ added in v0.9.0
AddProtocol marks the protocol as inheriting from another. This can only be called between AllocateProtocol and Protocol.Register.
func (*Protocol) CopyMethodDescriptionList ¶ added in v0.9.0
func (p *Protocol) CopyMethodDescriptionList(isRequiredMethod, isInstanceMethod bool) []MethodDescription
CopyMethodDescriptionList returns a list of methods that this protocol has given it isRequiredMethod and isInstanceMethod.
func (*Protocol) CopyPropertyList ¶ added in v0.9.0
CopyPropertyList returns a list of properties that this protocol has given it isRequiredProperty and isInstanceProperty.
func (*Protocol) CopyProtocolList ¶ added in v0.9.0
CopyProtocolList returns a list of the protocols that this protocol inherits from.
type SEL ¶
type SEL uintptr
SEL is an opaque type that represents a method selector
func RegisterName ¶
RegisterName registers a method with the Objective-C runtime system, maps the method name to a selector, and returns the selector value. This function grabs the global Objective-c lock. It is best the cache the result of this function.