Struct objc2_foundation::MainThreadMarker
source · pub struct MainThreadMarker { /* private fields */ }
Expand description
A marker type taken by functions that can only be executed on the main thread.
By design, this is neither Send
nor Sync
, and can only be created
on the main thread, meaning that if you’re holding this, you know you’re
running on the main thread.
See the following links for more information on main-thread-only APIs:
- Main Thread Only APIs on OS X
- Thread Safety Summary
- Are the Cocoa Frameworks Thread Safe?
- Technical Note TN2028 - Threading Architectures
- Thread Management
- Mike Ash’ article on thread safety
§Main Thread Checker
Xcode provides a tool called the “Main Thread Checker” which
verifies that UI APIs are being used from the correct thread. This is not
as principled as MainThreadMarker
, but is helpful for catching mistakes.
You can use this tool on macOS by loading libMainThreadChecker.dylib
into your process using DYLD_INSERT_LIBRARIES
:
DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/usr/lib/libMainThreadChecker.dylib MTC_RESET_INSERT_LIBRARIES=0 cargo run
If you’re not running your binary through Cargo, you can omit
MTC_RESET_INSERT_LIBRARIES
.
DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/usr/lib/libMainThreadChecker.dylib target/debug/myapp
If you’re developing for iOS, you probably better off enabling the tool in Xcode’s own UI.
See this excellent blog post for details on further configuration options.
§Examples
Use when designing APIs that are only safe to use on the main thread:
use objc2_foundation::{MainThreadMarker, NSObject};
use objc2::msg_send;
// This action requires the main thread, so we take a marker as parameter.
// It signals clearly to users "this requires the main thread".
unsafe fn do_thing(obj: *const NSObject, _mtm: MainThreadMarker) {
msg_send![obj, someActionThatRequiresTheMainThread]
}
// Usage
// Create a new marker. This requires the `"NSThread"` feature.
// If that is not available, create the marker unsafely with
// `new_unchecked`, after having checked that the thread is the main one
// through other means.
#[cfg(feature = "NSThread")]
let mtm = MainThreadMarker::new().expect("must be on the main thread");
#[cfg(not(feature = "NSThread"))]
let mtm = unsafe { MainThreadMarker::new_unchecked() };
unsafe { do_thing(obj, mtm) }
Implementations§
source§impl MainThreadMarker
impl MainThreadMarker
sourcepub fn new() -> Option<Self>
Available on crate feature NSThread
only.
pub fn new() -> Option<Self>
NSThread
only.Construct a new MainThreadMarker
.
Returns None
if the current thread was not the main thread.
sourcepub unsafe fn new_unchecked() -> Self
pub unsafe fn new_unchecked() -> Self
Construct a new MainThreadMarker
without first checking whether
the current thread is the main one.
§Safety
The current thread must be the main thread.
Alternatively, you may create this briefly if you know that a an API is safe in a specific case, but is not marked so. If you do that, you must ensure that any use of the marker is actually safe to do from another thread than the main one.
sourcepub fn alloc<T: ClassType>(self) -> Allocated<T>
pub fn alloc<T: ClassType>(self) -> Allocated<T>
Allocate a new instance of the specified class on the main thread.
This is essentially the same as ClassType::alloc
, the difference
being that it is also callable with classes that can only be used on
the main thread.
§Example
Create an object on the main thread.
use objc2_foundation::MainThreadMarker;
use objc2_app_kit::NSView as SomeClass; // An example class
use objc2::rc::Retained;
use objc2::msg_send_id;
let mtm = MainThreadMarker::new().expect("must be on the main thread");
// _All_ objects are safe to allocate on the main thread!
let obj = mtm.alloc::<SomeClass>();
// Though more knowledge is required for safe initialization
let obj: Retained<SomeClass> = unsafe { msg_send_id![obj, init] };
sourcepub fn run_on_main<F, R>(f: F) -> R
👎Deprecated: Use the free-standing function run_on_main
insteadAvailable on crate features dispatch
and NSThread
only.
pub fn run_on_main<F, R>(f: F) -> R
run_on_main
insteaddispatch
and NSThread
only.Submit the given closure to the runloop on the main thread.
Deprecated in favour of the free-standing function run_on_main
.
Trait Implementations§
source§impl Clone for MainThreadMarker
impl Clone for MainThreadMarker
source§fn clone(&self) -> MainThreadMarker
fn clone(&self) -> MainThreadMarker
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for MainThreadMarker
impl Debug for MainThreadMarker
source§impl<T: ?Sized + IsMainThreadOnly> From<&T> for MainThreadMarker
impl<T: ?Sized + IsMainThreadOnly> From<&T> for MainThreadMarker
Get a MainThreadMarker
from a main-thread-only object.
This function exists purely in the type-system, and will always succeed at runtime.
source§impl Hash for MainThreadMarker
impl Hash for MainThreadMarker
source§impl Ord for MainThreadMarker
impl Ord for MainThreadMarker
source§fn cmp(&self, other: &MainThreadMarker) -> Ordering
fn cmp(&self, other: &MainThreadMarker) -> Ordering
1.21.0 · source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
source§impl PartialEq for MainThreadMarker
impl PartialEq for MainThreadMarker
source§fn eq(&self, other: &MainThreadMarker) -> bool
fn eq(&self, other: &MainThreadMarker) -> bool
self
and other
values to be equal, and is used
by ==
.source§impl PartialOrd for MainThreadMarker
impl PartialOrd for MainThreadMarker
source§fn partial_cmp(&self, other: &MainThreadMarker) -> Option<Ordering>
fn partial_cmp(&self, other: &MainThreadMarker) -> Option<Ordering>
1.0.0 · source§fn le(&self, other: &Rhs) -> bool
fn le(&self, other: &Rhs) -> bool
self
and other
) and is used by the <=
operator. Read more