Skip to main content

StatefulView

Struct StatefulView 

Source
pub struct StatefulView {
    pub metadata: *const c_void,
    pub witness_table: *const c_void,
    pub id: i64,
    /* private fields */
}
Expand description

A runtime-built Swift view type with a real @State.

SwiftUI installs the storage itself: it walks the type’s reflection field records looking for a stored property whose type conforms to DynamicProperty, finds the State<Int>, and attaches a location box. That is what makes set invalidate the view and re-run the body, and what lets set_animated interpolate — a @State change is a change to a view SwiftUI already knows, unlike a root swap.

The catch is how quietly that walk fails. If the field’s mangled type name does not demangle, the runtime reports the field as an empty tuple, SwiftUI finds no DynamicProperty, and everything still works — the body runs once, writes report success — except nothing ever updates. See the layout assertions in build_type.

§Several at once

The body witness is one extern "C" function with no room for an instance parameter, so the struct carries a second stored field holding an id. The witness reads it and looks the right builder up, which is what lets more than one StatefulView be live at a time.

Fields§

§metadata: *const c_void

Metadata for the synthesised struct.

§witness_table: *const c_void

Its View witness table.

§id: i64

Identifies this instance to the shared body witness.

Implementations§

Source§

impl StatefulView

Source

pub fn new( initial: i64, builder: impl Fn(i64) -> ViewHandle + Send + 'static, ) -> Self

Build the type and one instance of it.

builder receives the current state value every time SwiftUI evaluates the body.

Hosting the result works: examples/parity’s state_rebuild check hosts one, writes to it three times, and asserts the body saw each new value. An earlier note here said it faulted in a value witness — that was true of the first attempt, which borrowed State<Int>’s witness table; the module docs explain why that cannot work and what replaced it.

Examples found in repository?
examples/ios_app.rs (line 61)
54fn root_view() -> views::ViewHandle {
55    thread_local! {
56        static ROOT: std::cell::OnceCell<swiftui_native::state::StatefulView> =
57            const { std::cell::OnceCell::new() };
58    }
59    ROOT.with(|cell| {
60        let sv = cell.get_or_init(|| {
61            let sv = swiftui_native::state::StatefulView::new(0, |_generation| ui());
62            ROOT_ID.store(sv.id, std::sync::atomic::Ordering::Release);
63            sv
64        });
65        sv.as_view()
66    })
67}
Source

pub fn set(&self, value: i64) -> bool

Write a new value, re-running the body.

Source

pub fn set_animated(&self, value: i64)

Write a new value inside withAnimation, so SwiftUI interpolates.

Source

pub fn set_animated_with(&self, value: i64, animation: u64)

As set_animated, with the animation spelled out — withAnimation(.easeInOut(duration: 1)) { ... } and the like.

Source

pub fn as_view(&self) -> ViewHandle

Wrap the instance in an AnyView so it can be hosted like any other view.

Examples found in repository?
examples/ios_app.rs (line 65)
54fn root_view() -> views::ViewHandle {
55    thread_local! {
56        static ROOT: std::cell::OnceCell<swiftui_native::state::StatefulView> =
57            const { std::cell::OnceCell::new() };
58    }
59    ROOT.with(|cell| {
60        let sv = cell.get_or_init(|| {
61            let sv = swiftui_native::state::StatefulView::new(0, |_generation| ui());
62            ROOT_ID.store(sv.id, std::sync::atomic::Ordering::Release);
63            sv
64        });
65        sv.as_view()
66    })
67}

Trait Implementations§

Source§

impl Drop for StatefulView

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.