pub fn autoreleasepool<T, F>(f: F) -> T where
    for<'p> F: FnOnce(&'p AutoreleasePool) -> T + AutoreleaseSafe
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 reference to the enclosing function to give it a lifetime parameter that autoreleased objects can refer to.

The given reference 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. You can test the compile error with the unstable-autoreleasesafe crate feature on nightly Rust.

Note that this is mostly useful for preventing leaks (as any Objective-C method may leak internally). If implementing an interface to an object, you should try to return retained pointers with msg_send_id! wherever you can instead, since having to use this function can be quite cumbersome for your users!

Examples

Basic usage:

use core::mem::ManuallyDrop;
use objc2::{class, msg_send, msg_send_id};
use objc2::rc::{autoreleasepool, AutoreleasePool, Id, Owned};
use objc2::runtime::Object;

fn needs_lifetime_from_pool<'p>(pool: &'p AutoreleasePool) -> &'p mut Object {
    let obj: Id<Object, Owned> = unsafe { msg_send_id![class!(NSObject), new] };
    let obj = ManuallyDrop::new(obj);
    let obj: *mut Object = unsafe { msg_send![obj, autorelease] };
    // Lifetime of the returned reference is bounded by the pool
    unsafe { pool.ptr_as_mut(obj) }

    // Or simply
    // let obj: Id<Object, Owned> = unsafe { msg_send_id![class!(NSObject), new] };
    // obj.autorelease(pool)
}

autoreleasepool(|pool| {
    // Create `obj` and autorelease it to the pool
    let obj = needs_lifetime_from_pool(pool);
    // ... use `obj` here
    // `obj` is deallocated when the pool ends
});

Fails to compile because obj does not live long enough for us to safely take it out of the pool:

let obj = autoreleasepool(|pool| {
    let obj = needs_lifetime_from_pool(pool);
    // Use `obj`
    obj
});

Incorrect usage which panics (with debug assertions enabled) because we tried to pass an outer pool to an inner pool:

autoreleasepool(|outer_pool| {
    let obj = autoreleasepool(|inner_pool| {
        let obj = needs_lifetime_from_pool(outer_pool);
        obj
    });
    // `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.
});