class
UI::NativeHandle
- UI::NativeHandle
- Reference
- Object
Overview
Wraps a raw Void* pointer to a platform-native object with explicit
ownership semantics determined by a ReleaseStrategy.
Deterministic Cleanup vs GC Safety Net
The preferred cleanup path is #release!, which immediately frees the
native resource and poisons the pointer to catch use-after-free bugs.
The #finalize method acts as a GC safety net for handles that were
not explicitly released -- it should NOT be relied upon as the primary
cleanup mechanism.
Thread Safety
NativeHandle instances are NOT thread-safe. A handle should be owned
by a single NativeView and released on the same thread that created it.
Usage
handle = UI::NativeHandle.new(some_ptr, UI::ReleaseStrategy::ObjCRelease, label: "NSButton")
handle.valid? # => true
handle.ptr! # => some_ptr (raises if released or null)
handle.release!
handle.valid? # => false
handle.release! # safe: idempotent, no-op on second call
Defined in:
ui/native/native_handle.crConstructors
Instance Method Summary
-
#finalize
GC safety net.
-
#label : String | Nil
Optional debug label identifying what this handle wraps.
-
#ptr : Pointer(Void)
The raw pointer to the platform-native object.
-
#ptr! : Pointer(Void)
Returns the raw pointer, raising if the handle has been released or the pointer is null.
-
#release! : Nil
Deterministic cleanup.
-
#released? : Bool
Whether
#release!has been called. -
#state_handle : Pointer(Void) | Nil
Optional reactive-state pointer (Phase 3 Remediation 4).
-
#state_handle=(state_handle : Pointer(Void) | Nil)
Optional reactive-state pointer (Phase 3 Remediation 4).
-
#strategy : ReleaseStrategy
The ownership strategy that determines how the pointer is released.
-
#valid? : Bool
Returns
trueif the handle wraps a non-null pointer and has not been released.
Constructor Detail
Instance Method Detail
GC safety net. If the handle was never explicitly released, attempt
to clean up the native resource. This is a last resort -- always
prefer calling #release! or NativeView#teardown! explicitly.
Optional debug label identifying what this handle wraps. Only used for diagnostics and leak tracking.
The raw pointer to the platform-native object.
After #release!, this is poisoned to Pointer(Void).null.
Returns the raw pointer, raising if the handle has been released or the pointer is null.
Use this when you need a guaranteed-valid pointer for FFI calls.
Raises Exception if the handle is released or wraps a null pointer.
Deterministic cleanup. Releases the native resource according to the strategy and poisons the pointer.
This method is idempotent: calling it multiple times is safe and has no effect after the first call.
Optional reactive-state pointer (Phase 3 Remediation 4).
When the wrapped platform view was constructed through one of the
apsk_make_*_reactive facade entry points, the Swift side allocates
an ObservableObject state container (APSKLabelState,
APSKButtonState, BoolStorage, DoubleStorage) and writes a +1
retained opaque pointer here. The matching Crystal mutator method
(UI::Label#text=, etc.) dispatches through this pointer to update
the published value, which drives a SwiftUI re-render of the hosted
subtree without rebuilding the view tree.
#release! drops the +1 retain via apsk_state_release so the state
object's lifetime tracks the platform view's. Nil when the handle
was built through the legacy non-reactive path or wraps a view that
does not participate in the reactive surface (every widget today
except Label / Button / Toggle / Slider).
Optional reactive-state pointer (Phase 3 Remediation 4).
When the wrapped platform view was constructed through one of the
apsk_make_*_reactive facade entry points, the Swift side allocates
an ObservableObject state container (APSKLabelState,
APSKButtonState, BoolStorage, DoubleStorage) and writes a +1
retained opaque pointer here. The matching Crystal mutator method
(UI::Label#text=, etc.) dispatches through this pointer to update
the published value, which drives a SwiftUI re-render of the hosted
subtree without rebuilding the view tree.
#release! drops the +1 retain via apsk_state_release so the state
object's lifetime tracks the platform view's. Nil when the handle
was built through the legacy non-reactive path or wraps a view that
does not participate in the reactive surface (every widget today
except Label / Button / Toggle / Slider).
The ownership strategy that determines how the pointer is released.