pub struct Retained<T: ?Sized> { /* private fields */ }
Expand description
A reference counted pointer type for Objective-C objects.
Retained
strongly references or “retains” the given object T
, and
decrements the retain count or “releases” it again when dropped, thereby
ensuring it will be deallocated at the right time.
The type T
inside Retained<T>
can be anything that implements
Message
.
T
’s ClassType
implementation (if any) determines whether it is
mutable, and by extension whether Retained<T>
is mutable.
This can usually be gotten from one of the methods in the framework
crates, but can be created manually with the msg_send_id!
macro (or
even more manually, with the Retained::retain
, Retained::from_raw
or Retained::retain_autoreleased
methods).
§Comparison to std
types
Retained<T>
can be thought of as kind of a weird combination of Arc
and Box
:
If T
implements IsMutable
(like it does on NSMutableString
and
NSMutableArray<_>
), Retained<T>
acts like Box<T>
, and allows mutable
/ unique access to the type.
Otherwise, which is the most common case, Retained<T>
acts like
Arc<T>
, and allows cloning by bumping the reference count.
§Forwarding implementations
Since Retained<T>
is a smart pointer, it Deref
s to T
, and
similarly implements DerefMut
when mutable.
It also forwards the implementation of a bunch of standard library traits
such as PartialEq
, AsRef
, and so on, so that it becomes possible
to use e.g. Retained<NSString>
as if it was NSString
. (Having
NSString
directly is not possible since Objective-C objects cannot live
on the stack, but instead must reside on the heap).
Note that because of current limitations in the Rust trait system, some
traits like Default
, IntoIterator
, FromIterator
, From
and
Into
are not directly implementable on NSString
; for that use-case,
we instead provide the DefaultRetained
, RetainedIntoIterator
and
RetainedFromIterator
traits, which make some of the the aforementioned
traits implementable on Retained
.
§Memory layout
This is guaranteed to have the same size and alignment as a pointer to the
object, *const T
.
Additionally, it participates in the null-pointer optimization, that is,
Option<Retained<T>>
is guaranteed to have the same size as
Retained<T>
.
§Example
Various usage of Retained
on an immutable object.
use objc2_foundation::{NSObject, NSString};
use objc2::rc::Retained;
use objc2::{ClassType, msg_send_id};
// Use `msg_send_id!` to create an `Retained` with correct memory management
//
// SAFETY: The types are correct, and it is safe to call the `new`
// selector on `NSString`.
let string: Retained<NSString> = unsafe { msg_send_id![NSString::class(), new] };
// Or:
// let string = NSString::new();
// Methods on `NSString` is usable via. `Deref`
#[cfg(not_available)]
assert_eq!(string.len(), 0);
// Bump the reference count of the object (possible because the object is
// immutable, would not be possible for `NSMutableString`).
let another_ref: Retained<NSString> = string.clone();
// Convert one of the references to a reference to `NSObject` instead
let obj: Retained<NSObject> = Retained::into_super(string);
// And use the `Debug` impl from that
assert_eq!(format!("{obj:?}"), "");
// Finally, the `Retained`s go out of scope, the reference counts are
// decreased, and the string will deallocate
Implementations§
source§impl<T: ?Sized + Message> Retained<T>
impl<T: ?Sized + Message> Retained<T>
sourcepub unsafe fn from_raw(ptr: *mut T) -> Option<Self>
pub unsafe fn from_raw(ptr: *mut T) -> Option<Self>
Construct an Retained
from a pointer that already has +1 retain count.
Returns None
if the pointer was NULL.
This is useful when you have a retain count that has been handed off
from somewhere else, usually Objective-C methods like init
, alloc
,
new
, copy
, or methods with the ns_returns_retained
attribute.
If you do not have +1 retain count, such as if your object was
retrieved from other methods than the ones noted above, use
Retained::retain
instead.
§Safety
You must uphold the same requirements as described in Retained::retain
.
Additionally, you must ensure the given object pointer has +1 retain count.
§Example
Comparing different ways of creating a new NSObject
.
use objc2::rc::Retained;
use objc2::runtime::NSObject;
use objc2::{msg_send, msg_send_id, ClassType};
// Manually using `msg_send!` and `Retained::from_raw`
let obj: *mut NSObject = unsafe { msg_send![NSObject::class(), alloc] };
let obj: *mut NSObject = unsafe { msg_send![obj, init] };
// SAFETY: `-[NSObject init]` returns +1 retain count
let obj: Retained<NSObject> = unsafe { Retained::from_raw(obj).unwrap() };
// Or with `msg_send_id!`
let obj: Retained<NSObject> = unsafe { msg_send_id![NSObject::alloc(), init] };
// Or using the `NSObject::new` method
let obj = NSObject::new();
sourcepub unsafe fn new(ptr: *mut T) -> Option<Self>
👎Deprecated: use the more descriptive name Retained::from_raw
instead
pub unsafe fn new(ptr: *mut T) -> Option<Self>
Retained::from_raw
insteadsourcepub fn into_raw(this: Self) -> *mut T
pub fn into_raw(this: Self) -> *mut T
Consumes the Retained
, returning a raw pointer with +1 retain count.
After calling this function, the caller is responsible for the memory
previously managed by the Retained
.
This is effectively the opposite of Retained::from_raw
, see that for
more details on when this function is useful.
§Examples
Converting an Retained
to a pointer and back.
use objc2::rc::Retained;
use objc2::runtime::NSObject;
let obj = NSObject::new();
let ptr = Retained::into_raw(obj);
// SAFETY: The pointer is valid, and has +1 retain count from above.
let obj = unsafe { Retained::from_raw(ptr) }.unwrap();
sourcepub fn as_ptr(this: &Self) -> *const T
pub fn as_ptr(this: &Self) -> *const T
Returns a raw pointer to the object.
The pointer is valid for at least as long as the Retained
is held.
See Retained::as_mut_ptr
for the mutable equivalent.
This is an associated method, and must be called as Retained::as_ptr(obj)
.
sourcepub fn as_mut_ptr(this: &mut Self) -> *mut Twhere
T: IsMutable,
pub fn as_mut_ptr(this: &mut Self) -> *mut Twhere
T: IsMutable,
Returns a raw mutable pointer to the object.
The pointer is valid for at least as long as the Retained
is held.
See Retained::as_ptr
for the immutable equivalent.
This is an associated method, and must be called as
Retained::as_mut_ptr(obj)
.
source§impl<T: Message> Retained<T>
impl<T: Message> Retained<T>
sourcepub unsafe fn cast<U: Message>(this: Self) -> Retained<U> ⓘ
pub unsafe fn cast<U: Message>(this: Self) -> Retained<U> ⓘ
Convert the type of the given object to another.
This is equivalent to a cast
between two pointers.
See Retained::into_super
and ProtocolObject::from_retained
for
safe alternatives.
This is common to do when you know that an object is a subclass of
a specific class (e.g. casting an instance of NSString
to NSObject
is safe because NSString
is a subclass of NSObject
).
All 'static
objects can safely be cast to AnyObject
, since that
assumes no specific class.
§Safety
You must ensure that the object can be reinterpreted as the given type.
If T
is not 'static
, you must ensure that U
ensures that the
data contained by T
is kept alive for as long as U
lives.
Additionally, you must ensure that any safety invariants that the new type has are upheld.
Note that it is not in general safe to cast e.g. Retained<NSString>
to
Retained<NSMutableString>
, even if you’ve checked at runtime that the
object is an instance of NSMutableString
! This is because
Retained<NSMutableString>
assumes the string is unique, whereas it may
have been cloned while being an Retained<NSString>
.
sourcepub unsafe fn retain(ptr: *mut T) -> Option<Retained<T>>
pub unsafe fn retain(ptr: *mut T) -> Option<Retained<T>>
Retain the pointer and construct an Retained
from it.
Returns None
if the pointer was NULL.
This is useful when you have been given a pointer to an object from some API, and you would like to ensure that the object stays around while you work on it.
For normal Objective-C methods, you may want to use
Retained::retain_autoreleased
instead, as that is usually more
performant.
See ClassType::retain
for a safe alternative.
§Safety
If the object is mutable, the caller must ensure that there are no
other pointers or references to the object, such that the returned
Retained
pointer is unique.
Additionally, the pointer must be valid as a reference (aligned,
dereferencable and initialized, see the std::ptr
module for more
information) or NULL.
Finally, you must ensure that any data that T
may reference lives
for at least as long as T
.
sourcepub unsafe fn retain_autoreleased(ptr: *mut T) -> Option<Retained<T>>
pub unsafe fn retain_autoreleased(ptr: *mut T) -> Option<Retained<T>>
Retains a previously autoreleased object pointer.
This is useful when calling Objective-C methods that return autoreleased objects, see Cocoa’s Memory Management Policy.
This has exactly the same semantics as Retained::retain
, except it can
sometimes avoid putting the object into the autorelease pool, possibly
yielding increased speed and reducing memory pressure.
Note: This relies heavily on being inlined right after msg_send!
,
be careful to not accidentally require instructions between these.
§Safety
Same as Retained::retain
.
sourcepub fn autorelease_ptr(this: Self) -> *mut T
pub fn autorelease_ptr(this: Self) -> *mut T
Autoreleases the Retained
, returning a pointer.
The object is not immediately released, but will be when the innermost / current autorelease pool (given as a parameter) is drained.
This is useful when defining your own classes and you have some error
parameter passed as Option<&mut *mut NSError>
, and you want to
create and autorelease an error before returning.
See Retained::autorelease
and Retained::autorelease_mut
for alternatives
that yield safe references.
This is an associated method, and must be called as
Retained::autorelease_ptr(obj)
.
sourcepub fn autorelease<'p>(this: Self, pool: AutoreleasePool<'p>) -> &'p T
pub fn autorelease<'p>(this: Self, pool: AutoreleasePool<'p>) -> &'p T
Autoreleases the Retained
, returning a reference bound to the pool.
The object is not immediately released, but will be when the innermost / current autorelease pool (given as a parameter) is drained.
See Retained::autorelease_mut
for the mutable alternative.
This is an associated method, and must be called as
Retained::autorelease(obj, pool)
.
sourcepub fn autorelease_mut<'p>(this: Self, pool: AutoreleasePool<'p>) -> &'p mut Twhere
T: IsMutable,
pub fn autorelease_mut<'p>(this: Self, pool: AutoreleasePool<'p>) -> &'p mut Twhere
T: IsMutable,
Autoreleases the Retained
, returning a mutable reference bound to the
pool.
The object is not immediately released, but will be when the innermost / current autorelease pool (given as a parameter) is drained.
See Retained::autorelease
for the immutable alternative.
This is an associated method, and must be called as
Retained::autorelease_mut(obj, pool)
.
sourcepub fn autorelease_return(this: Self) -> *mut T
pub fn autorelease_return(this: Self) -> *mut T
Autoreleases and prepares the Retained
to be returned to Objective-C.
The object is not immediately released, but will be when the innermost autorelease pool is drained.
This is useful when declaring your own methods where you will often find yourself in need of returning autoreleased objects to properly follow Cocoa’s Memory Management Policy.
To that end, you could use Retained::autorelease
, but that would require
you to have an AutoreleasePool
object at hand, which you often
won’t have in such cases. This function doesn’t require a pool
object (but as a downside returns a pointer instead of a reference).
This is also more efficient than a normal autorelease
, since it
makes a best effort attempt to hand off ownership of the retain count
to a subsequent call to objc_retainAutoreleasedReturnValue
/
Retained::retain_autoreleased
in the enclosing call frame.
This optimization relies heavily on this function being tail called, so make sure you only call this function at the end of your method.
§Example
Returning an Retained
from a declared method (note: the declare_class!
macro supports doing this for you automatically).
use objc2::{class, msg_send_id, sel};
use objc2::declare::ClassBuilder;
use objc2::rc::Retained;
use objc2::runtime::{AnyClass, AnyObject, Sel};
let mut builder = ClassBuilder::new("ExampleObject", class!(NSObject)).unwrap();
extern "C" fn get(cls: &AnyClass, _cmd: Sel) -> *mut AnyObject {
let obj: Retained<AnyObject> = unsafe { msg_send_id![cls, new] };
Retained::autorelease_return(obj)
}
unsafe {
builder.add_class_method(
sel!(get),
get as extern "C" fn(_, _) -> _,
);
}
let cls = builder.register();
Trait Implementations§
source§impl<T: ?Sized + IsMutable> BorrowMut<T> for Retained<T>
impl<T: ?Sized + IsMutable> BorrowMut<T> for Retained<T>
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T: BufRead + ?Sized + IsMutable> BufRead for Retained<T>
impl<T: BufRead + ?Sized + IsMutable> BufRead for Retained<T>
source§fn fill_buf(&mut self) -> Result<&[u8]>
fn fill_buf(&mut self) -> Result<&[u8]>
source§fn consume(&mut self, amt: usize)
fn consume(&mut self, amt: usize)
amt
bytes have been consumed from the buffer,
so they should no longer be returned in calls to read
. Read moresource§fn read_line(&mut self, buf: &mut String) -> Result<usize>
fn read_line(&mut self, buf: &mut String) -> Result<usize>
0xA
byte) is reached, and append
them to the provided String
buffer. Read moresource§fn has_data_left(&mut self) -> Result<bool, Error>
fn has_data_left(&mut self) -> Result<bool, Error>
buf_read_has_data_left
)Read
has any data left to be read. Read moresource§fn skip_until(&mut self, byte: u8) -> Result<usize, Error>
fn skip_until(&mut self, byte: u8) -> Result<usize, Error>
bufread_skip_until
)byte
or EOF is reached. Read moresource§impl<T: ?Sized> Drop for Retained<T>
impl<T: ?Sized> Drop for Retained<T>
#[may_dangle]
(see this) doesn’t apply here since we
don’t run T
’s destructor (rather, we want to discourage having T
s with
a destructor); and even if we did run the destructor, it would not be safe
to add since we cannot verify that a dealloc
method doesn’t access
borrowed data.
source§impl<T: Error + ?Sized> Error for Retained<T>
impl<T: Error + ?Sized> Error for Retained<T>
source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · source§fn description(&self) -> &str
fn description(&self) -> &str
source§impl<T, U: RetainedFromIterator<T>> FromIterator<T> for Retained<U>
impl<T, U: RetainedFromIterator<T>> FromIterator<T> for Retained<U>
source§fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self
source§impl<T: Hasher + ?Sized + IsMutable> Hasher for Retained<T>
impl<T: Hasher + ?Sized + IsMutable> Hasher for Retained<T>
source§fn write_u128(&mut self, i: u128)
fn write_u128(&mut self, i: u128)
u128
into this hasher.source§fn write_usize(&mut self, i: usize)
fn write_usize(&mut self, i: usize)
usize
into this hasher.source§fn write_i128(&mut self, i: i128)
fn write_i128(&mut self, i: i128)
i128
into this hasher.source§fn write_isize(&mut self, i: isize)
fn write_isize(&mut self, i: isize)
isize
into this hasher.source§fn write_length_prefix(&mut self, len: usize)
fn write_length_prefix(&mut self, len: usize)
hasher_prefixfree_extras
)source§impl<'a, T: ?Sized> IntoIterator for &'a Retained<T>where
&'a T: IntoIterator,
impl<'a, T: ?Sized> IntoIterator for &'a Retained<T>where
&'a T: IntoIterator,
source§impl<'a, T: ?Sized + IsMutable> IntoIterator for &'a mut Retained<T>where
&'a mut T: IntoIterator,
impl<'a, T: ?Sized + IsMutable> IntoIterator for &'a mut Retained<T>where
&'a mut T: IntoIterator,
source§impl<T: ?Sized + RetainedIntoIterator> IntoIterator for Retained<T>
impl<T: ?Sized + RetainedIntoIterator> IntoIterator for Retained<T>
source§impl<T: Ord + ?Sized> Ord for Retained<T>
impl<T: Ord + ?Sized> Ord for Retained<T>
source§impl<T: PartialOrd + ?Sized> PartialOrd for Retained<T>
impl<T: PartialOrd + ?Sized> PartialOrd for Retained<T>
source§fn le(&self, other: &Self) -> bool
fn le(&self, other: &Self) -> bool
self
and other
) and is used by the <=
operator. Read moresource§impl<T: Read + ?Sized + IsMutable> Read for Retained<T>
impl<T: Read + ?Sized + IsMutable> Read for Retained<T>
source§fn read(&mut self, buf: &mut [u8]) -> Result<usize>
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
source§fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
read
, except that it reads into a slice of buffers. Read moresource§fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize>
buf
. Read moresource§fn read_to_string(&mut self, buf: &mut String) -> Result<usize>
fn read_to_string(&mut self, buf: &mut String) -> Result<usize>
buf
. Read moresource§fn read_exact(&mut self, buf: &mut [u8]) -> Result<()>
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()>
buf
. Read moresource§fn is_read_vectored(&self) -> bool
fn is_read_vectored(&self) -> bool
can_vector
)source§fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<(), Error>
fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<(), Error>
read_buf
)source§fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<(), Error>
fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> Result<(), Error>
read_buf
)cursor
. Read more1.0.0 · source§fn by_ref(&mut self) -> &mut Selfwhere
Self: Sized,
fn by_ref(&mut self) -> &mut Selfwhere
Self: Sized,
Read
. Read moresource§impl<T: Seek + ?Sized + IsMutable> Seek for Retained<T>
impl<T: Seek + ?Sized + IsMutable> Seek for Retained<T>
source§fn seek(&mut self, pos: SeekFrom) -> Result<u64>
fn seek(&mut self, pos: SeekFrom) -> Result<u64>
source§fn stream_position(&mut self) -> Result<u64>
fn stream_position(&mut self) -> Result<u64>
1.55.0 · source§fn rewind(&mut self) -> Result<(), Error>
fn rewind(&mut self) -> Result<(), Error>
source§impl<T: Write + ?Sized + IsMutable> Write for Retained<T>
impl<T: Write + ?Sized + IsMutable> Write for Retained<T>
source§fn write(&mut self, buf: &[u8]) -> Result<usize>
fn write(&mut self, buf: &[u8]) -> Result<usize>
source§fn flush(&mut self) -> Result<()>
fn flush(&mut self) -> Result<()>
source§fn write_all(&mut self, buf: &[u8]) -> Result<()>
fn write_all(&mut self, buf: &[u8]) -> Result<()>
source§fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()>
fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()>
source§fn is_write_vectored(&self) -> bool
fn is_write_vectored(&self) -> bool
can_vector
)impl<T: Eq + ?Sized> Eq for Retained<T>
impl<T: ?Sized + RefUnwindSafe> RefUnwindSafe for Retained<T>
impl<T: ?Sized + ClassType + Send> Send for Retained<T>where
T::Mutability: SendSyncHelper<T>,
EquivalentType<T>: Send,
Retained<T>
is always Send
if T
is Send + Sync
.
Additionally, for mutable types, T
doesn’t have to be Sync
(only
requires T: Send
), since it has unique access to the object.
impl<T: ?Sized + ClassType + Sync> Sync for Retained<T>where
T::Mutability: SendSyncHelper<T>,
EquivalentType<T>: Sync,
Retained<T>
is always Sync
if T
is Send + Sync
.
Additionally, for mutable types, T
doesn’t have to be Send
(only
requires T: Sync
), since it has unique access to the object.