macro_rules! sel { (new) => { ... }; (init) => { ... }; (alloc) => { ... }; (dealloc) => { ... }; ($sel:ident) => { ... }; ($($sel:ident :)*) => { ... }; ($($sel:tt)*) => { ... }; }
Expand description
Register a selector with the Objective-C runtime.
Returns the Sel
corresponding to the specified selector.
§Panics
Panics if the runtime failed allocating space for the selector.
§Specification
This has similar syntax and functionality as the @selector
directive in
Objective-C.
This calls Sel::register
internally. The result is cached for
efficiency. The cache for certain common selectors (alloc
, init
and
new
) is deduplicated to reduce code-size.
Non-ascii identifiers are ill-tested, if supported at all.
§Features
If the experimental "unstable-static-sel"
feature is enabled, this will
emit special statics that will be replaced by the dynamic linker (dyld)
when the program starts up - in exactly the same manner as normal
Objective-C code does.
This should be significantly faster (and allow better native debugging),
however due to the Rust compilation model, and since we don’t have
low-level control over it, it is currently unlikely that this will work
correctly in all cases.
See the source code and rust-lang/rust#53929 for more info.
Concretely, this may fail at:
- link-time (likely)
- dynamic link-time/just before the program is run (fairly likely)
- runtime, causing UB (unlikely)
The "unstable-static-sel-inlined"
feature is the even more extreme
version - it yields the best performance and is closest to real
Objective-C code, but probably won’t work unless your code and its
inlining is written in a very certain way.
Enabling LTO greatly increases the chance that these features work.
§Examples
Get a few different selectors:
use objc2::sel;
let sel = sel!(alloc);
let sel = sel!(description);
let sel = sel!(_privateMethod);
let sel = sel!(storyboardWithName:bundle:);
let sel = sel!(
otherEventWithType:
location:
modifierFlags:
timestamp:
windowNumber:
context:
subtype:
data1:
data2:
);
Whitespace is ignored:
let sel1 = sel!(setObject:forKey:);
let sel2 = sel!( setObject :
forKey : );
assert_eq!(sel1, sel2);
Invalid selector:
let sel = sel!(aSelector:withoutTrailingColon);
A selector with internal colons:
let sel = sel!(sel::with:::multiple:internal::::colons:::);
// Yes, that is possible! The following Objective-C would work:
//
// @interface MyThing: NSObject
// + (void)test:(int)a :(int)b arg:(int)c :(int)d;
// @end
Unsupported usage that you may run into when using macros - fails to
compile when the "unstable-static-sel"
feature is enabled.
Instead, define a wrapper function that retrieves the selector.
use objc2::sel;
macro_rules! x {
($x:ident) => {
// One of these is fine
sel!($x);
// But using the identifier again in the same way is not!
sel!($x);
};
}
// Identifier `abc`
x!(abc);