Function objc2::rc::autoreleasepool
source · pub fn autoreleasepool<T, F>(f: F) -> T
Expand description
Execute f
in the context of a new autorelease pool. The pool is drained
after the execution of f
completes.
This corresponds to @autoreleasepool
blocks in Objective-C and Swift.
The pool is passed as a parameter to the closure to give you a lifetime parameter that autoreleased objects can refer to.
Note that this is mostly useful for preventing leaks (as any Objective-C
method may autorelease internally - see also autoreleasepool_leaking
).
If implementing an interface to an object, you should try to return
retained pointers with msg_send_id!
wherever you can instead, since
it is usually more efficient, and having to use this function can be quite
cumbersome for users.
§Restrictions
The given parameter must not be used in an inner autoreleasepool
- doing
so will panic with debug assertions enabled, and be a compile error in a
future release.
Note that this means that this function is currently unsound, since it doesn’t disallow wrong usage in all cases. Enabling the assertions in release mode would be prohibitively expensive though, so this is the least-bad solution.
You can try to compile your crate with the "unstable-autoreleasesafe"
crate feature enabled on nightly Rust - if your crate compiles with that,
its autoreleasepool usage is guaranteed to be correct.
§Examples
Basic usage:
use objc2::rc::{autoreleasepool, Retained};
use objc2::runtime::NSObject;
autoreleasepool(|pool| {
// Create `obj` and autorelease it to the pool
let obj = Retained::autorelease(NSObject::new(), pool);
// We now have a reference that we can freely use
println!("{obj:?}");
// `obj` is deallocated when the pool ends
});
// And is no longer usable outside the closure
Fails to compile because obj
does not live long enough for us to take it
out of the pool:
use objc2::rc::{autoreleasepool, Retained};
use objc2::runtime::NSObject;
let obj = autoreleasepool(|pool| {
Retained::autorelease(NSObject::new(), pool)
});
Fails to compile with the "unstable-autoreleasesafe"
feature enabled, or
panics with debug assertions enabled, because we tried to pass an outer
pool to an inner pool:
use objc2::rc::{autoreleasepool, Retained};
use objc2::runtime::NSObject;
autoreleasepool(|outer_pool| {
let obj = autoreleasepool(|inner_pool| {
Retained::autorelease(NSObject::new(), outer_pool)
});
// `obj` could wrongly be used here because its lifetime was
// assigned to the outer pool, even though it was released by the
// inner pool already.
});
It is impossible to extend the lifetime of the pool.
use std::cell::RefCell;
use objc2::rc::{autoreleasepool, AutoreleasePool};
thread_local! {
static POOL: RefCell<Option<&'static AutoreleasePool<'static>>> = RefCell::new(None);
}
autoreleasepool(|pool| {
POOL.with(|p| {
*p.borrow_mut() = Some(Box::leak(Box::new(pool)))
});
});