//! Note: We can't use the `define_class!` macro for this, it doesn't support //! such use-cases (yet). Instead, we'll create it manually. #![deny(unsafe_op_in_unsafe_fn)] use std::cell::Cell; use std::marker::PhantomData; use std::sync::Once;
use objc2::rc::Retained; use objc2::runtime::{AnyClass, AnyObject, ClassBuilder, NSObject}; use objc2::{msg_send, ClassType, Encoding, Message, RefEncode};
/// The type of the instance variable that we want to store type Ivar<'a> = &'a Cell<u8>;
/// Struct that represents our custom object. #[repr(C)] struct MyObject<'a> { /// Required to give MyObject the proper layout /// /// Beware: `retain`-ing this field directly is dangerous, since it'd make /// it possible to extend the lifetime of the object beyond lifetime `'a`.
inner: AnyObject, /// For auto traits and variance
p: PhantomData<Ivar<'a>>,
}
let _cls = builder.register();
});
AnyClass::get(c"MyObject").unwrap()
}
fn new(number: &'a mut u8) -> Retained<Self> { // SAFETY: The instance variable is initialized below. let this: Retained<Self> = unsafe { msg_send![Self::class(), new] };
// It is generally very hard to use `mut` in Objective-C, so let's use // interior mutability instead. let number = Cell::from_mut(number);
let ivar = Self::class().instance_variable(c"number").unwrap(); // SAFETY: The ivar is added with the same type below, and the // lifetime of the reference is properly bound to the class. unsafe { ivar.load_ptr::<Ivar<'_>>(&this.inner).write(number) };
this
}
fn get(&self) -> u8 { let ivar = Self::class().instance_variable(c"number").unwrap(); // SAFETY: The ivar is added with the same type below, and is initialized in `new` unsafe { ivar.load::<Ivar<'_>>(&self.inner).get() }
}
fn set(&self, number: u8) { let ivar = Self::class().instance_variable(c"number").unwrap(); // SAFETY: The ivar is added with the same type below, and is initialized in `new` unsafe { ivar.load::<Ivar<'_>>(&self.inner).set(number) };
}
}
fn main() { letmut number = 54;
let obj = MyObject::new(&mut number);
assert_eq!(obj.get(), 54);
// We can now mutate the referenced `number`
obj.set(7);
assert_eq!(obj.get(), 7);
// And we can clone the object, since we use interior mutability. let clone = obj.clone();
clone.set(42);
assert_eq!(obj.get(), 42);
drop(clone);
// It is not possible to convert to `Retained<NSObject>`, since that would // loose the lifetime information that `MyObject` stores. // // let obj = obj.into_super(); // // Neither is it not possible to access `number` any more, since `obj` // holds a mutable reference to it. // // assert_eq!(number, 42);
drop(obj); // And now that we've dropped `obj`, we can access `number` again
assert_eq!(number, 42);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.