objc

package
v0.6.18 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 10 Imported by: 2

Documentation

Overview

Package objc provides cached Objective-C runtime helpers.

This package wraps purego/objc to provide selector caching for better performance.

Index

Constants

This section is empty.

Variables

View Source
var ErrInitFailed = errors.New("objc: initializer returned nil")

ErrInitFailed reports that an Objective-C initializer returned nil without filling in its NSError out-parameter. Wrapping that nil would hand the caller an object that only fails once it is used, far from the cause.

View Source
var ErrUnrecognizedSelector = errors.New("unrecognized selector")

ErrUnrecognizedSelector is the sentinel error for an unavailable selector.

Functions

func AddMethod

func AddMethod(cls Class, sel SEL, impl IMP, types string) bool

AddMethod adds a new method to a class. impl is an Objective-C method implementation, such as the result of NewIMP.

func AssociateBlockWithReceiver added in v0.6.1

func AssociateBlockWithReceiver(receiver ID, key *byte, block Block)

AssociateBlockWithReceiver ties the lifetime of block to receiver via objc_setAssociatedObject with OBJC_ASSOCIATION_RETAIN_NONATOMIC.

When the receiver deallocates, the Objective-C runtime releases the associated block, which invokes purego's dispose callback and clears the Go closure from the block cache.

Passing the same key on a subsequent call replaces the prior association: the runtime releases the previous block before retaining the new one. This is the mechanism used by setter-style escaping methods (set*Block:, set*Handler:, set*Callback:) to free the prior block when overwritten.

Keys are package-level vars emitted by applegen at each call site, so a caller outside generated code has no need to construct one. The block must be a Go-owned block returned by NewBlock; the caller transfers ownership.

func AutoreleasePool added in v0.5.0

func AutoreleasePool(fn func())

AutoreleasePool executes fn within an Objective-C autorelease pool. Any autoreleased objects created during fn are released when fn returns.

AutoreleasePool pins the calling goroutine to its OS thread (via runtime.LockOSThread) for the duration of fn because Objective-C autorelease pools are thread-affine and must be popped on the thread that pushed them.

func BytesPointer added in v0.6.17

func BytesPointer(b []byte) unsafe.Pointer

BytesPointer returns a C pointer to b's backing array, or nil when b is empty.

unsafe.SliceData returns a non-nil pointer for an empty but non-nil slice, and for a nil slice it returns nil only by accident of the current implementation. Callees that take a byte buffer treat NULL as "no bytes"; handing them a pointer to zero-sized storage instead makes them read past the end of it. Every generated call site that passes a []byte to Objective-C goes through here so the empty case is spelled NULL exactly once.

func CallWithError

func CallWithError(id ID, sel SEL, args ...any) error

CallWithError calls a void-returning selector and handles the NSError** pattern.

func ClearActionTarget added in v0.6.17

func ClearActionTarget(owner ID)

ClearActionTarget removes the action trampoline associated with owner, releasing it immediately. It is safe to call when no trampoline is set.

func ConvertSlice

func ConvertSlice[T any](ids []ID, convert func(ID) T) []T

ConvertSlice maps []ID to []T using a converter function.

func ConvertSliceToStrings

func ConvertSliceToStrings(ids []ID) []string

ConvertSliceToStrings maps []ID to []string via IDToString.

func GoString

func GoString(cstr *byte) string

GoString converts a C string (*byte from UTF8String) to a Go string. This is needed because UTF8String returns const char*, not an ObjC object.

func GoStringPtr added in v0.5.3

func GoStringPtr(cstr *byte) *string

GoStringPtr converts a nullable C string to a heap-backed *string.

func IDToString

func IDToString(id ID) string

IDToString converts an NSString ID to a Go string.

func IDToStringPtr added in v0.5.3

func IDToStringPtr(id ID) *string

IDToStringPtr converts a nullable NSString ID to a heap-backed *string.

func MustSend

func MustSend[T any](id ID, sel SEL, args ...any) T

MustSend calls a selector and panics with a clear error if the object doesn't respond. Use this when you expect the selector to always exist but want a clearer panic message than the NSInvalidArgumentException.

func NewActionTarget

func NewActionTarget(owner ID, fn func(sender ID)) (target ID, sel SEL)

NewActionTarget creates an Objective-C trampoline object that calls fn when it receives the "invoke:" selector. The trampoline is associated with owner via objc_setAssociatedObject so it is retained for the owner's lifetime and cleaned up automatically when the owner is deallocated or a new action target replaces it.

Returns the trampoline ID and the selector to wire as the action.

func RegisterClassPair

func RegisterClassPair(cls Class)

RegisterClassPair registers a class pair with the runtime.

func RespondsToSelector

func RespondsToSelector(id ID, sel SEL) bool

RespondsToSelector checks if an object responds to the given selector. This is the safe way to check before calling a method.

func SafeSend

func SafeSend[T any](id ID, sel SEL, args ...any) (T, error)

SafeSend calls a selector only if the object responds to it. Returns the zero value and an error matching ErrUnrecognizedSelector if the selector is not recognized. This prevents NSInvalidArgumentException crashes from unrecognized selectors.

func Send

func Send[T any](id ID, sel SEL, args ...any) T

Send calls objc_msgSend with the given arguments.

When all arguments are uintptr-sized primitives (ID, SEL, Class, uintptr, bool, or integer types) and T is ID or struct{}, Send uses a pre-registered typed function instead of the general argument-processing path: 300ns and 4 allocations against 520ns and 8 allocations under -tags objc_slowpath, so roughly 1.7x. The pre-registered functions still allocate; purego's RegisterFunc calls reflect.New on every invocation.

Otherwise Send falls back to purego/objc with full argument processing: IDGetter extraction, nil→ID(0), CArrayArg conversion, and NSArray→[]ID.

Send keeps values in args alive until the Objective-C call returns, and that reaches through unsafe.Pointer arguments: an unsafe.Pointer is a reference the garbage collector can see, so keeping one alive also keeps alive the storage it points into, including when it points into the interior of a larger object. A caller passing unsafe.Pointer(unsafe.SliceData(b)) — which is what BytesPointer returns — therefore does not need its own runtime.KeepAlive(b); the backing array survives the call. TestSendKeepsSliceAliveThroughDerivedPointer holds this property down, and fails if the KeepAlive below is removed.

What Send cannot protect is storage behind a uintptr. A uintptr is a plain integer that the collector does not trace, so a caller must never convert a pointer to uintptr before handing it to Send; pass the unsafe.Pointer.

func SendIfResponds added in v0.6.17

func SendIfResponds[T any](id ID, sel SEL, args ...any) T

SendIfResponds calls a selector if the receiver responds to it and returns the zero value if it does not.

It exists for bindings to private frameworks, where a selector may simply be absent: Apple ships no compatibility guarantee for them, and a selector that exists on one macOS build can be gone on the next. Sending to a receiver that does not respond raises NSInvalidArgumentException, which for a Go process is not an exception but an abort -- there is no recover, and the process dies inside the Objective-C runtime with a stack that does not name the caller.

Returning the zero value is deliberately quiet, and that is a real tradeoff: a caller cannot tell "the selector is missing" from "the call returned zero". Use SafeSend where the caller can act on the difference. This variant is for generated bindings, whose signatures are fixed by the Objective-C method and have nowhere to put an error, and where the alternative is not a better error but a dead process.

The receiver may be an instance or a class: NSObject implements respondsToSelector: on both, so a class object correctly reports its class methods.

func SendSuper added in v0.6.17

func SendSuper[T any](id ID, sel SEL, args ...any) T

SendSuper sends sel to the superclass of id's class.

SendSuper derives the starting class from id's dynamic class, so it is only correct for methods on leaf classes. A method inherited by a further subclass would recurse into itself.

func SendWithError

func SendWithError[T any](id ID, sel SEL, args ...any) (T, error)

SendWithError calls a selector that uses the NSError** pattern. It assumes the method accepts an NSError** as its last argument. It automatically appends the error pointer to the arguments.

func SetBlockSignature added in v0.6.10

func SetBlockSignature(block Block, signature []byte) bool

SetBlockSignature sets the Objective-C runtime signature for block. The signature storage must outlive block.

See NewBlock for details on standard ("@?") vs extended ("@?<...>") block type encodings.

func SetNSErrorBlockSignature added in v0.6.10

func SetNSErrorBlockSignature(block Block) bool

SetNSErrorBlockSignature sets block's signature to a single NSError argument.

func ValueAt added in v0.6.17

func ValueAt[T any](addr uintptr) T

ValueAt loads a value of type T from a symbol address.

Dlsym returns the address of a global in a loaded Mach-O image, so reading an exported constant means dereferencing that address at the constant's type. The memory is not Go-managed and does not move, which is what makes the uintptr round trip safe here — go vet cannot prove that, so it flags the conversion. Doing it once, here, keeps the generated packages from repeating an unsafe conversion several hundred times.

The zero value is returned for a nil address.

Types

type Block

type Block = pobjc.Block

Type aliases for convenience

func NewBlock

func NewBlock(fn any) Block

NewBlock creates an Objective-C block from a Go function. The Go function must take a Block as its first argument. Use Block.Release() to free the block when it is no longer in use.

Method type encodings from method_getTypeEncoding render block arguments as bare "@?", with no inner signature. Extended signatures ("@?<...>") carrying parameter types come from protocol extended method types (_protocol_getMethodTypeEncoding) or block descriptors.

type CArrayArg

type CArrayArg struct {
	// contains filtered or unexported fields
}

CArrayArg marks a Go slice argument that should be passed to Objective-C as a pointer to contiguous C array storage.

Use CArray at call sites for APIs that take `*T` and a paired `count` parameter.

func CArray

func CArray(v any) CArrayArg

CArray marks a slice argument for C-array pointer conversion in Send.

type Class

type Class = pobjc.Class

Type aliases for convenience

func GetClass

func GetClass(name string) Class

GetClass returns the class with the exact given name.

func RegisterClass

func RegisterClass(name string, superClass Class, protocols []*Protocol, ivars []FieldDef, methods []MethodDef) (Class, error)

RegisterClass registers a new Objective-C class with the runtime. The class inherits from superClass and implements the given protocols. ivars defines instance variables, methods defines the class methods.

type FieldDef

type FieldDef = pobjc.FieldDef

Type aliases for convenience

type ID

type ID = pobjc.ID

Type aliases for convenience

func IDFrom

func IDFrom(ptr unsafe.Pointer) ID

IDFrom converts a raw pointer to an ID.

func IDValueAt added in v0.3.6

func IDValueAt(addr uintptr) ID

IDValueAt loads an Objective-C object ID stored at a symbol address.

Dynamic libraries commonly export Objective-C object constants as pointers to storage containing the real object ID. Dlsym returns the storage address, so callers must load the pointer-sized value stored there.

func NSArrayToSlice

func NSArrayToSlice(array ID) []ID

NSArrayToSlice converts an NSArray ID into a []ID by calling count and objectAtIndex:.

func String

func String(s string) ID

String converts a Go string to an autoreleased NSString object.

Callers on a thread without a run loop should enclose work that creates strings in AutoreleasePool. Otherwise autoreleased strings can accumulate for the lifetime of the thread.

type IDGetter

type IDGetter interface {
	GetID() ID
}

IDGetter is implemented by types that wrap an Objective-C object ID. This allows objc.Send to automatically extract the ID from wrapper types.

type IMP added in v0.6.17

type IMP = pobjc.IMP

Type aliases for convenience

func NewIMP added in v0.6.17

func NewIMP(fn any) IMP

NewIMP returns an Objective-C method implementation for fn.

fn must take (ID, SEL) as its first two arguments, because that is how the runtime calls every method: the receiver and the selector arrive in the first two registers whether or not the Go function declares them. A function missing that prefix reads the receiver as its first declared argument and every later argument shifts, which corrupts the call silently rather than failing. NewIMP panics instead.

The returned implementation is never deallocated.

type MethodDef

type MethodDef = pobjc.MethodDef

Type aliases for convenience

type ObjCError added in v0.6.17

type ObjCError struct {
	ID ID
}

ObjCError is an Objective-C error returned through an NSError** parameter. ID is the underlying NSError object.

func (ObjCError) Error added in v0.6.17

func (e ObjCError) Error() string

Error returns the localized error description with its domain and code.

type Protocol

type Protocol = pobjc.Protocol

Type aliases for convenience

func GetProtocol

func GetProtocol(name string) *Protocol

GetProtocol returns the protocol with the given name, or nil if not found.

type SEL

type SEL = pobjc.SEL

Type aliases for convenience

func RegisterName

func RegisterName(name string) SEL

RegisterName registers a selector with the Objective-C runtime. This is the same as Sel but without caching - use Sel for repeated calls.

func Sel

func Sel(name string) SEL

Sel returns a cached selector for the given name. This avoids the global lock in pobjc.RegisterName on repeated calls.

type UnrecognizedSelectorError

type UnrecognizedSelectorError struct {
	Selector string
}

UnrecognizedSelectorError records a selector an object does not respond to.

func (*UnrecognizedSelectorError) Error

func (e *UnrecognizedSelectorError) Error() string

func (*UnrecognizedSelectorError) Unwrap added in v0.6.0

func (e *UnrecognizedSelectorError) Unwrap() error

Directories

Path Synopsis
Package objcbridge contains small Objective-C runtime helpers.
Package objcbridge contains small Objective-C runtime helpers.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL