Macro objc2::msg_send_id
source · macro_rules! msg_send_id { [$obj:expr, $selector:ident $(,)?] => { ... }; [$obj:expr, $($selector:ident : $argument:expr),+ $(,)?] => { ... }; }
Expand description
msg_send!
for methods returning id
, NSObject*
, or similar object
pointers.
Object pointers in Objective-C have certain rules for when they should be
retained and released across function calls. This macro helps doing that,
and returns an rc::Id
with the object, optionally wrapped in an
Option
if you want to handle failures yourself.
A little history
Objective-C’s type system is… limited, so you can’t easily tell who is responsible for releasing an object. To remedy this problem, Apple/Cocoa introduced approximately the following rule:
The caller is responsible for releasing objects return from methods that
begin with new
, alloc
, copy
, mutableCopy
or init
, and method
that begins with init
takes ownership of the receiver. See Cocoa’s
Memory Management Policy for a user-friendly introduction to
this concept.
In the past, users had to do retain
and release
calls themselves to
properly follow these rules. To avoid the memory management problems
associated with manual stuff like that, they introduced “ARC”,
which codifies the rules as part of the language, and inserts the required
retain
and release
calls automatically.
msg_send!
is similar to pre-ARC; you have to know when to retain and
when to release an object. msg_send_id!
is similar to ARC; the rules
are simple enough that we can do them automatically!
Specification
The syntax is the same as in msg_send!
.
Attributes like objc_method_family
, ns_returns_retained
, ns_consumed
and so on must not present on the method - if they are, you should do
manual memory management using the msg_send!
macro instead.
The accepted receiver and return types, and how we handle them, differ
depending on which, if any, of the recognized selector
families the selector belongs to (here T: Message
and
O: Ownership
):
-
The
new
family: The receiver must be&Class
, and the return type is a genericId<T, O>
orOption<Id<T, O>>
. -
The
alloc
family: The receiver must be&Class
, and the return type is a genericId<Allocated<T>, O>
orOption<Id<Allocated<T>, O>>
. -
The
init
family: The receiver must beOption<Id<Allocated<T>, O>>
as returned fromalloc
. The receiver is consumed, and a the now-initializedId<T, O>
orOption<Id<T, O>>
(with the sameT
andO
) is returned. -
The
copy
family: The receiver may be anything that implementsMessageReceiver
and the return type is a genericId<T, O>
orOption<Id<T, O>>
. -
The
mutableCopy
family: Same as thecopy
family. -
No family: The receiver may be anything that implements
MessageReceiver
. The result is retained usingId::retain_autoreleased
, and a genericId<T, O>
orOption<Id<T, O>>
is returned. This retain is in most cases faster than using autorelease pools!
See the clang documentation for the precise specification of Objective-C’s ownership rules.
As you may have noticed, the return type is always either Id<_, _>
or
Option<Id<_, _>>
. Internally, the return type is always
Option<Id<_, _>>
(for example: almost all new
methods can fail if the
allocation failed), but for convenience, if the return type is Id<_, _>
this macro will automatically unwrap the object, or panic with an error
message if it couldn’t be retrieved.
This macro doesn’t support super methods yet, see #173.
The retain
, release
and autorelease
selectors are not supported, use
Id::retain
, Id::drop
and Id::autorelease
for that.
Panics
Panics if the return type is specified as Id<_, _>
and the method
returned NULL.
Additional panicking cases are documented in msg_send!
.
Safety
Same as msg_send!
, with an expected return type of id
,
instancetype
, NSObject*
, or other such object pointers. The method
must not have any attributes that changes the how it handles memory
management.
Note that if you’re using this inside a context that expects unwinding to
have Objective-C semantics (like exception::catch
), you should make
sure that the return type is Option<Id<_, _>>
so that you don’t get an
unexpected unwind through incompatible ABIs!
Examples
use objc2::{class, msg_send_id};
use objc2::ffi::NSUInteger;
use objc2::rc::{Id, Shared};
use objc2::runtime::Object;
let obj = unsafe { msg_send_id![class!(NSObject), alloc] };
// Consume the allocated object, return initialized object
let obj: Id<Object, Shared> = unsafe { msg_send_id![obj, init] };
// Copy the object
let copy: Id<Object, Shared> = unsafe { msg_send_id![&obj, copy] };
// Call ordinary selector that returns an object
// This time, we handle failures ourselves
let s: Option<Id<Object, Shared>> = unsafe { msg_send_id![&obj, description] };
let s = s.expect("description was NULL");