NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
crates.io · #773 most downloaded on crates.io
Objective-C interface and runtime bindings
Last release 2 days ago
05 Oct 2026
Ships fairly regularly
a new release about every 4 months
Nearly every release is documented
notes for 13 of 13 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
29 releases · first in 2021
One column per quarter.
Bump objc2 0.6.4 -> 0.6.5
Bump objc2 0.6.3 -> 0.6.4
Fix documentation on docs.rs
chore: Release objc2 version 0.6.2
chore: Release objc2 version 0.6.1
Merged and deprecated the following ffi types:
AnyClass::is_metaclass.MainThreadMarker from objc2-foundation.
MainThreadMarker::new_unchecked and MainThreadBound::new is now available
in const. This is useful for creating main-thread only statics.MainThreadMarker::from now debug-asserts that it is actually running on
the main thread.MainThreadOnly::mtm.DowncastTarget, AnyObject::downcast_ref and Retained::downcast
to allow safely casting between Objective-C objects.fmt traits on Retained.Extend trait on Retained.AsRef in a forwarding fashion on Retained.PartialEq and PartialOrd on Retained in a slightly more
generic way.Into to convert to retained objects.Retained::into_super an inherent method instead of an associated
method. This means that you can now use it as .into_super().available!() macro for determining whether code is running on
a given operating system.Message for AnyClass and AnyProtocol.AnyClass and AnyProtocol to be converted to AnyObject (both of
these can act as objects).define_class! now implement Send and Sync when
subclassing NSObject.Encode and RefEncode impls for function pointers
(previously only implemented for up to 12 arguments, which turned out to be
insufficient).#[unsafe(method_family = ...)] attribute in extern_methods!,
extern_protocol! and define_class!, to allow overriding the inferred
method family if need be.PartialEq, Eq, Hash, PartialOrd and Ord implementations for
Bool."disable-encoding-assertions" Cargo feature flag to allow completely
disabling encoding verification.BREAKING: Renamed declare_class! to define_class!, and changed the
syntax to be more succinct:
// Before
use objc2::mutability::InteriorMutable;
use objc2::runtime::{NSObject, NSObjectProtocol};
use objc2::{declare_class, ClassType, DeclaredClass};
struct MyIvars;
declare_class!(
struct MyObject;
unsafe impl ClassType for MyObject {
type Super = NSObject;
type Mutability = InteriorMutable;
const NAME: &'static str = "MyObject";
}
impl DeclaredClass for MyObject {
type Ivars = MyIvars;
}
unsafe impl MyObject {
#[method(myMethod)]
fn my_method(&self) {
// ...
}
}
unsafe impl NSObjectProtocol for MyObject {}
);
// After
use objc2::runtime::{NSObject, NSObjectProtocol};
use objc2::define_class;
struct MyIvars;
define_class!(
#[unsafe(super(NSObject))]
#[name = "MyObject"]
#[ivars = MyIvars]
struct MyObject;
impl MyObject {
#[unsafe(method(myMethod))]
fn my_method(&self) {
// ...
}
}
unsafe impl NSObjectProtocol for MyObject {}
);
Whether classes are only available on the main thread is now automatically inferred, and you only need to overwrite it if your class is doing something different than its superclass.
BREAKING: Changed the syntax of extern_class! to be more succinct:
// Before
use objc2::mutability::MainThreadOnly;
use objc2::runtime::NSObject;
use objc2::{extern_class, ClassType};
extern_class!(
#[derive(PartialEq, Eq, Hash, Debug)]
struct MyClass;
unsafe impl ClassType for MyClass {
type Super = NSObject;
type ThreadKind = dyn MainThreadOnly;
const NAME: &'static str = "MyClass";
}
);
// After
use objc2::runtime::NSObject;
use objc2::{extern_class, MainThreadOnly};
extern_class!(
#[unsafe(super(NSObject))]
#[thread_kind = MainThreadOnly]
#[name = "MyClass"]
#[derive(PartialEq, Eq, Hash, Debug)]
struct MyClass;
);
BREAKING: Changed the syntax of extern_protocol! to be more succinct:
// Before
extern_protocol!(
unsafe trait MyProtocol {
#[method(myMethod)]
fn myMethod(&self);
}
// The line below is now unnecessary
unsafe impl ProtocolType for dyn MyProtocol {}
);
// After
extern_protocol!(
unsafe trait MyProtocol {
#[unsafe(method(myMethod))]
fn myMethod(&self);
}
);
BREAKING: Changed the syntax of extern_methods! to push the unsafe inside:
// Before
extern_methods!(
unsafe impl MyObject {
#[method(myMethod)]
fn myMethod(&self);
}
);
// After
impl MyObject {
extern_methods!(
#[unsafe(method(myMethod))]
fn myMethod(&self);
);
}
BREAKING: Moved the common retain and alloc methods from ClassType
to Message and AllocAnyThread/MainThreadOnly, respectively.
// Before
use objc2::ClassType;
let my_obj = MyObject::init(MyObject::alloc());
let retained = my_obj.retain();
// After
use objc2::{Message, AllocAnyThread}; // Need different trait imports
let my_obj = MyObject::init(MyObject::alloc());
let retained = my_obj.retain();
Print backtrace when catching exceptions with the "catch-all" feature.
Changed the return value of ClassBuilder::add_protocol to indicate whether
the protocol was already present on the class or not.
Merged objc-sys into this crate's ffi module.
BREAKING: Changed the signature of various ffi functions to no longer
accept nullable function pointers.
BREAKING: Changed the signature of various ffi functions to use the
proper Bool type instead of a typedef.
Made exception::catch safe.
Merged and deprecated the following ffi types:
ffi::objc_class is merged into runtime::AnyClass.ffi::objc_object is merged into runtime::AnyObject.ffi::objc_protocol is merged into runtime::AnyProtocol.ffi::IMP is merged into runtime::Imp.ffi::objc_method is merged into runtime::Method.ffi::objc_ivar is merged into runtime::Ivar.ffi::BOOL and constants is merged into runtime::Bool.Deprecated ffi::id. Use AnyObject instead.
Deprecated NSObjectProtocol::is_kind_of, use isKindOfClass or the new
AnyObject::downcast_ref method instead.
Deprecated Retained::cast, this has been renamed to Retained::cast_unchecked.
Renamed DeclaredClass to DefinedClass.
Merged msg_send! and msg_send_id!. The latter is now deprecated.
Merged #[method(...)] and #[method_id(...)] in extern_methods! and
extern_protocol!. #[method_id(...)] is now deprecated.
Deprecated rc::Weak::from_id. Use rc::Weak::from_retained instead.
Deprecated ProtocolObject::from_id. Use ProtocolObject::from_retained
instead.
Deprecated using msg_send! without a comma between arguments.
See the following for an example of how to upgrade:
// Before
let _: NSInteger = msg_send![
obj,
addTrackingRect:rect
owner:obj
userData:ptr::null_mut::<c_void>()
assumeInside:Bool::NO
];
// After
let _: NSInteger = msg_send![
obj,
addTrackingRect: rect, // Added comma
owner: obj, // Added comma
userData: ptr::null_mut::<c_void>(), // Added comma
assumeInside: false, // Added comma (optional when trailing)
];
ffi::SEL and ffi::objc_selector types. Use
runtime::Sel instead.ffi exception function pointer aliases.mutability::HasStableHash._mut methods:
Retained::as_mut_ptr.Retained::autorelease_mut.DeclaredClass::ivars_mut.ProtocolObject::from_mut.AutoreleasePool::ptr_as_mut.ClassType::as_super_mut.&mut message receivers (except in the special case
when the object is AnyObject, for better backwards compatibility with
objc).AsMut, BorrowMut and DerefMut implementations in
extern_class! and declare_class!.mutability module, and everything within.
Classes now always use interior mutability.DerefMut implementation for Retained<T> when the
Retained was mutable.Retained::autorelease as unsafe, since we cannot
ensure that the given pool is actually the innermost pool.malloc feature and malloc_buf dependency.DefaultId, IdFromIterator and
IdIntoIterator, as well as their methods. Use the renamed traits instead.ClassType manually, to make
it easier to evolve the API going forwards.apple Cargo feature flag.msg_send_id![cls, alloc] to a call to
the faster runtime function objc_alloc no longer works, use
AllocAnyThread::alloc or MainThreadOnly::alloc instead.Remove an incorrect assertion when adding protocols to classes in an unexpected order.
BREAKING: Converted function signatures into using extern "C-unwind"
where applicable. This allows Rust and Objective-C unwinding to interoperate.
BREAKING: Use CStr in methods in the runtime module, since it's both
more performant, and more correct. Use the new c"my_str" syntax to migrate.
Specifically, this includes:
ClassBuilder::new.ClassBuilder::root.ClassBuilder::add_ivar.ProtocolBuilder::new.Sel::register.Sel::name.Ivar::name.Ivar::type_encoding.Method::return_type.Method::argument_type.AnyClass::get.AnyClass::name.AnyClass::instance_variable.AnyProtocol::get.AnyProtocol::name.Clarified that exception::catch does not catch Rust panics.
Improved the Debug impl when deriving via extern_class!.
Generic objects now always implement common traits PartialEq, Eq and
Hash, instead of guarding them behind T: Message.
Prevented main thread only classes created using declare_class! from
automatically implementing the auto traits Send and Sync.
BREAKING: Fixed the signature of NSObjectProtocol::isEqual to take a
nullable argument.
Fixed handling of methods that return NULL errors. This affected for example
-[MTLBinaryArchive serializeToURL:error:].
Fixed unwinding while using writeback / error parameters.
Bump objc2 0.5.2 -> 0.5.3
The old name is kept as a soft-deprecated type-alias (will be fully deprecated in v0.6.0).
Retained::autorelease_ptr."relax-sign-encoding", which when enabled, allows
using e.g. NSInteger in places where you would otherwise have to use
NSUInteger.Renamed Id to Retained, to better reflect what it represents.
The old name is kept as a soft-deprecated type-alias (will be fully
deprecated in v0.6.0).
The same is done for:
rc::WeakId to rc::Weak.rc::DefaultId to rc::DefaultRetained.rc::IdFromIterator to rc::RetainedFromIterator.rc::IdIntoIterator to rc::RetainedIntoIterator.apple Cargo feature flag, it is assumed by default on Apple
platforms.Moved ClassBuilder and ProtocolBuilder from the declare module to the runtime module. The old locations are deprecated.
"malloc" feature
flag:
Method::return_type.Method::argument_type.AnyClass::classes.AnyClass::instance_methods.AnyClass::adopted_protocols.AnyClass::instance_variables.AnyProtocol::protocols.AnyProtocol::adopted_protocols.Id::into_raw as the oppositve of Id::from_raw.NSObjectProtocol:
isEqual.hash.isKindOfClass.isMemberOfClass.respondsToSelector.conformsToProtocol.description.debugDescription.isProxy.retainCount.NSObject::init.NSObject::doesNotRecognizeSelector.ClassBuilder and ProtocolBuilder from the declare module to the
runtime module. The old locations are deprecated."verify" feature flag's functionality when debug assertions are
enabled.Id::new to Id::from_raw. The previous name is kept as a
deprecated alias.[0.5.0]: https://github.com/madsmtm/objc2/compare/objc2-0.4.1...objc2-0.5.0
mutability module (see the documentation
for motivation and usage info):
HasStableHash.IsAllowedMutable.IsMainThreadOnly.CounterpartOrSelf.encode traits EncodeReturn, EncodeArgument and
EncodeArguments.as_ptr and as_mut_ptr to Allocated.msg_send_id![cls, alloc] to a call to
the faster runtime function objc_alloc.DeclaredClass, which represents classes that are declared in Rust.Allocated::set_ivars, which sets the instance variables of an
object, and returns the new rc::PartialInit.msg_send_id! to call super methods.Send and Sync for ProtocolObject if the underlying protocol
implements it.Send and Sync versions of
ProtocolObject<dyn NSObjectProtocol>.BREAKING: Changed how instance variables work in declare_class!.
Previously, instance variables had to implement Encode, and you had to
initialize them properly, which was difficult to ensure.
Now, you implement the new DeclaredClass trait instead, which helps to
ensure all of this for you.
// Before
declare_class!(
struct MyObject {
object: IvarDrop<Id<NSObject>, "_object">,
data: IvarDrop<Option<Box<MyData>>, "_data">,
}
mod ivars;
unsafe impl ClassType for MyObject {
type Super = NSObject;
type Mutability = InteriorMutable;
const NAME: &'static str = "MyObject";
}
unsafe impl MyObject {
#[method(init)]
unsafe fn init(this: *mut Self) -> Option<NonNull<Self>> {
let this: Option<&mut Self> = msg_send![super(this), init];
this.map(|this| {
Ivar::write(&mut this.object, NSObject::new());
Ivar::write(&mut this.data, Box::new(MyData::new()));
NonNull::from(this)
})
}
}
);
extern_methods!(
unsafe impl MyObject {
#[method_id(new)]
pub fn new() -> Id<Self>;
}
);
fn main() {
let obj = MyObject::new();
println!("{:?}", obj.object);
}
// After
struct MyIvars {
object: Id<NSObject>,
data: Option<Box<MyData>>,
}
declare_class!(
struct MyObject;
unsafe impl ClassType for MyObject {
type Super = NSObject;
type Mutability = InteriorMutable;
const NAME: &'static str = "MyObject";
}
impl DeclaredClass for MyObject {
type Ivars = MyIvars;
}
unsafe impl MyObject {
#[method_id(init)]
pub fn init(this: Allocated<Self>) -> Option<Id<Self>> {
let this = this.set_ivars(MyIvars {
object: NSObject::new(),
data: MyData::new(),
});
unsafe { msg_send_id![super(this), init] }
}
}
);
extern_methods!(
unsafe impl MyObject {
#[method_id(new)]
pub fn new() -> Id<Self>;
}
);
fn main() {
let obj = MyObject::new();
println!("{:?}", obj.ivars().object);
}
BREAKING: AnyClass::verify_sel now take more well-defined types
EncodeArguments and EncodeReturn.
BREAKING: Changed how the mutability traits work; these no longer have
ClassType as a super trait, allowing them to work for ProtocolObject as
well.
This effectively means you can now copy a ProtocolObject<dyn NSCopying>.
BREAKING: Allow implementing DefaultId for any type, not just those
who are IsAllocableAnyThread.
BREAKING: Moved the MethodImplementation trait from the declare
module to the runtime module.
BREAKING: Moved the MessageReceiver trait to the runtime module.
BREAKING: Make the MessageReceiver trait no longer implemented for
references to Id. Dereference the Id yourself.
Note: Passing &Id in msg_send! is still supported.
BREAKING: MessageReceiver::send_message and
MessageReceiver::send_super_message now take EncodeArguments and return
EncodeReturn, instead of internal traits.
This is done to make MessageReceiver more straightforward to understand,
although it now also has slightly less functionality than msg_send!.
In particular automatic conversion of bool is not supported in
MessageReceiver.
Relaxed the requirements for receivers in MethodImplementation; now,
anything that implements MessageReceiver can be used as the receiver of
a method.
BREAKING: Renamed the associated types Ret and Args on
MethodImplementation to Return and Arguments.
BREAKING: Make rc::Allocated allowed to be NULL internally, such
that uses of Option<Allocated<T>> is now simply Allocated<T>.
AnyObject::class now returns a 'static reference to the class.
Relaxed ProtocolType requirement on ProtocolObject.
BREAKING: Updated encode types to those from objc2-encode v4.0.0.
Fixed the name of the protocol that NSObjectProtocol references.
Allow cloning Id<AnyObject>.
BREAKING: Restrict message sending to &mut references to things that
implement IsAllowedMutable.
Disallow the ability to use non-Self-like types as the receiver in
declare_class!.
Allow adding instance variables with the same name on Apple platforms.
BREAKING: Make loading instance variables robust and sound in the face of instance variables with the same name.
To read or write the instance variable for an object, you should now use the
load, load_ptr and load_mut methods on Ivar, instead of the ivar,
ivar_ptr and ivar_mut methods on AnyObject.
This is more verbose, but it also ensures that the class for the instance variable you're loading is the same as the one the instance variable you want to access is defined on.
// Before
let number = unsafe { *obj.ivar::<u32>("number") };
// After
let ivar = cls.instance_variable("number").unwrap();
let number = unsafe { *ivar.load::<u32>(&obj) };
Implement RefEncode normally for c_void. This makes AtomicPtr<c_void>
implement Encode.
BREAKING: Removed ProtocolType implementation for NSObject.
Use the more precise NSObjectProtocol trait instead!
BREAKING: Removed the MessageArguments trait.
BREAKING: Removed the following items from the declare module: Ivar,
IvarEncode, IvarBool, IvarDrop, IvarType and InnerIvarType.
Ivar functionality is available in a different form now, see above under "Changed".
BREAKING: Removed ClassBuilder::add_static_ivar.
This is technically a breaking change, but it should allow this crate to be compiled together with pre-release versions of it, meaning that in practic…
MainThreadMarker in extern_methods!."relax-void-encoding", which when enabled, allows
using *mut c_void in a few places where you would otherwise have to
specify the encoding precisely.Renamed runtime types:
Object to AnyObject.Class to AnyClass.Protocol to AnyProtocol.To better fit with Swift's naming scheme. The types are still available under the old names as deprecated aliases.
BREAKING: Updated encode types to those from objc2-encode v3.0.0.
This is technically a breaking change, but it should allow this crate to be compiled together with pre-release versions of it, meaning that in practice strictly more code out there will compile because of this. Hence it was deemed the better trade-off.
[0.4.0]: https://github.com/madsmtm/objc2/compare/objc2-0.3.0-beta.5...objc2-0.4.0
Added objc2::rc::autoreleasepool_leaking, and improve performance of
objects Debug impls.
BREAKING: Added associated type ClassType::Mutability, which replaces
the ownership type on Id, and must be specified for all class types.
An example:
// Before
use objc2::runtime::NSObject;
use objc2::{declare_class, ClassType};
declare_class!(
struct MyDelegate;
unsafe impl ClassType for MyDelegate {
type Super = NSObject;
}
// ... methods
);
// After
use objc2::runtime::NSObject;
use objc2::mutability::InteriorMutable;
use objc2::{declare_class, ClassType};
declare_class!(
struct MyDelegate;
unsafe impl ClassType for MyDelegate {
type Super = NSObject;
type Mutability = InteriorMutable; // Added
}
// ... methods
);
Added ClassType::retain, which is a safe way to go from a reference &T
to an Id<T>.
Added mutability module, containing various types that can be specified
for the above.
Preliminary support for specifying where bounds on methods inside
extern_protocol! and extern_methods!.
Allow arbitrary expressions in const NAME in extern_class!,
extern_protocol! and declare_class!.
Added rc::IdIntoIterator helper trait and forwarding IntoIterator
implementations for rc::Id.
Added rc::IdFromIterator helper trait for implementing IntoIterator
for rc::Id.
Added Display impl for runtime::Class, runtime::Sel and
runtime::Protocol.
Added Debug impl for runtime::Method and runtime::Ivar.
Added Method::set_implementation.
Added Method::exchange_implementation.
Added Object::set_class.
BREAKING: objc2::rc::AutoreleasePool is now a zero-sized Copy type
with a lifetime parameter, instead of the lifetime parameter being the
reference it was behind.
BREAKING: Made Id::autorelease and Id::autorelease_return be
associated functions instead of methods. This means they now have to be
called as Id::autorelease(obj, pool) instead of obj.autorelease(pool).
Additionally, rename the mutable version to Id::autorelease_mut.
BREAKING: Moved VerificationError, ProtocolObject and
ImplementedBy into the runtime module.
Relaxed a fmt::Debug bound on WeakId's own fmt::Debug impl.
Changed Debug impl for runtime::Class, runtime::Sel and
runtime::Protocol to give more information.
BREAKING: Updated encode module to objc2-encode v2.0.0.
exception::catch.BREAKING: Removed rc::SliceId, since it is implementable outside
objc2 from the layout guarantees of rc::Id.
BREAKING: Removed Ownership type parameter from Id, as well as
rc::Ownership, rc::Owned, rc::Shared, Id::from_shared and
Id::into_shared. This functionality has been moved from being at the
"usage-level", to being moved to the "type-level" in the associated type
ClassType::Mutability.
While being slightly more restrictive, it should vastly help you avoid
making mistakes around mutability (e.g. it is usually a mistake to make a
mutable reference &mut to an Objective-C object).
An example:
// Before
use objc2::rc::{Id, Shared};
use objc2::runtime::NSObject;
use objc2::msg_send_id;
let obj: Id<NSObject, Shared> = unsafe { msg_send_id![NSObject::class(), new] };
// After
use objc2::rc::Id;
use objc2::runtime::NSObject;
use objc2::msg_send_id;
let obj: Id<NSObject> = unsafe { msg_send_id![NSObject::class(), new] };
BREAKING: Removed impl<T> TryFrom<WeakId<T>> for Id<T> impl since it
did not have a proper error type, making it less useful than WeakId::load.
BREAKING: Removed forwarding Iterator implementation for Id, since
it conflicts with the IntoIterator implementation that it now has instead.
Deprecated the unstable function try_catch, it is exposed in objc2-exception-helper instead.
Support #[cfg(...)] attributes in extern_class! macro.
Added support for selectors with multiple colons like abc:: in the sel!,
extern_class!, extern_protocol! and declare_class! macros.
Added ability to use #[method_id(mySelector:)] inside declare_class!,
like you would do in extern_methods!.
Added 16-fold impls for EncodeArguments, MessageArguments, and MethodImplementation.
Added NSObjectProtocol trait for allowing ProtocolObject to implement
Debug, Hash, PartialEq and Eq.
Support running Drop impls on dealloc in declare_class!.
Added declare::IvarEncode and declare::IvarBool types.
BREAKING: Moved the objc2_encode traits to objc2::encode.
This includes removing the EncodeConvert and EncodeArguments traits.
Added support for out-parameters like &mut Id<_, _> in msg_send!,
msg_send_id! and extern_methods!.
BREAKING: Using the automatic NSError**-to-Result functionality in
extern_methods! now requires a trailing underscore (so now it's
#[method(myMethod:error:_)] instead of #[method(myMethod:error:)]).
BREAKING: Fundamentally changed how protocols work. Instead of being structs with inherent methods, they're now traits. This means that you can use their methods more naturally from your Objective-C objects.
An example:
// Before
extern_protocol!(
struct MyProtocol;
unsafe impl ProtocolType for MyProtocol {
#[method(myMethod)]
fn myMethod(&self);
}
);
let obj: &SomeObjectThatImplementsTheProtocol = ...;
let proto: &MyProtocol = obj.as_protocol();
proto.myMethod();
// After
extern_protocol!(
unsafe trait MyProtocol {
#[method(myMethod)]
fn myMethod(&self);
}
unsafe impl ProtocolType for dyn MyProtocol {}
);
let obj: &SomeObjectThatImplementsTheProtocol = ...;
obj.myMethod();
// Or
let proto: &ProtocolObject<dyn MyProtocol> = ProtocolObject::from_ref(obj);
proto.myMethod();
The ConformsTo trait has similarly been removed, and the ImplementedBy
trait and ProtocolObject struct has been introduced instead.
BREAKING: Moved NSObject::is_kind_of to the new NSObjectProtocol.
BREAKING: Removed support for custom dealloc impls in
declare_class!. Implement Drop for the type instead.
BREAKING: Changed how the declare_class! macro works.
Now, you must explicitly specify the "kind" of ivar you want, as well as the ivar name. Additionally, the class name must be explicitly specified.
This change is done to make it easier to see what's going on beneath the hood (the name will be available in the final binary, which is important to be aware of)!
An example:
// Before
declare_class!(
struct MyClass {
pub ivar: u8,
another_ivar: bool,
box_ivar: IvarDrop<Box<i32>>,
}
unsafe impl ClassType for MyClass {
type Super = NSObject;
}
);
// After
declare_class!(
struct MyClass {
pub ivar: IvarEncode<u8, "_ivar">,
another_ivar: IvarBool<"_another_ivar">,
box_ivar: IvarDrop<Box<i32>, "_box_ivar">,
}
// Helper types for ivars will be put in here
mod ivars;
unsafe impl ClassType for MyClass {
type Super = NSObject;
const NAME: &'static str = "MyClass";
}
);
Updated ffi module to objc-sys v0.3.0. This includes:
free method (same as libc::free).README.md to docs.rs.objc_terminate, object_isClass, objc_alloc and
objc_allocWithZone now that Rust's macOS deployment target is 10.12.links key from objc_0_2 to objc_0_3 (so
DEP_OBJC_0_2_CC_ARGS in build scripts becomes DEP_OBJC_0_3_CC_ARGS).rust_objc_sys_0_2_try_catch_exception to
try_catch.try_catch, it is exposed in
objc2-exception-helper instead.BREAKING: Updated encode module to objc2-encode v2.0.0-pre.4.
declare_class! macro.extern_methods! without the ClassType trait in scope.declare_class!.() being possible in argument position in msg_send!.Fixed using deprecated attributes in declare_class!.
Allow directly specifying class name in extern_class! macro.
Added ClassType::alloc.
This means you can now simplify your code as follows:
// Before
let obj: Id<NSObject, Shared> = unsafe {
msg_send_id![msg_send_id![NSObject::class(), alloc], init]
};
// After
let obj: Id<NSObject, Shared> = unsafe {
msg_send_id![NSObject::alloc(), init]
};
Added Class::class_method.
Added the ability to specify error: _, somethingReturningError: _ and
so on at the end of msg_send!/msg_send_id!, and have it automatically
return a Result<..., Id<NSError, Shared>>.
Added the ability to specify an extra parameter at the end of the selector
in methods declared with extern_methods!, and let that be the NSError**
parameter.
Added #[method_id(...)] attribute to extern_methods!.
Added "verify" feature as a replacement for the "verify_message"
feature.
Added extern_protocol! macro and ProtocolType trait.
Added ConformsTo trait for marking that a type conforms to a specific
protocol.
Added Encode impl for Option<Sel>.
Added objc2::runtime::NSObject - before, this was only available under
objc2::foundation::NSObject.
Added objc2::runtime::NSZone - before, this was only available under
objc2::foundation::NSZone.
&Class as the receiver in msg_send_id! methods
of the new family.Allocated struct to be used as Allocated<T>
instead of Id<Allocated<T>, O>.verify feature is enabled.declare_class! that protocols are implemented correctly.extern_methods
from #[sel(...)] to #[method(...)].extern_methods! and declare_class! such that
associated functions whose first parameter is called this, is treated as
instance methods instead of class methods.debug_assertions enabled if they are detected to
be invalid. Test your code to see if that is the case!declare_class! uses ConformsTo<...> instead of the
temporary Protocol<...> syntax.Message to support weak references.objc2::foundation into icrate::Foundation.objc2::ns_string into icrate::ns_string.ffi module to objc-sys v0.2.0-beta.3. This includes:
encode module objc2-encode v2.0.0-pre.3.extern_methods!.deprecated attributes in declare_class!.cfg attributes on methods and implementations in declare_class!."verify_message" feature. It has been mostly
replaced by debug_assertions and the "verify" feature.Nothing published for this version
Nothing published for this version
Nothing published for this version
[0.3.0-beta.3]: https://github.com/madsmtm/objc2/compare/objc2-0.3.0-beta.2...objc2-0.3.0-beta.3
Ivar::write, Ivar::as_ptr and Ivar::as_mut_ptr for safely
querying and modifying instance variables inside init methods.IvarDrop<T> to allow storing complex Drop values in ivars
(currently rc::Id<T, O>, Box<T>, Option<rc::Id<T, O>> or
Option<Box<T>>).ClassType::NAME constant for statically
determining the name of a specific class.declare_class! macro.MaybeUninit no longer implements IvarType directly; use
Ivar::write instead.Deprecated msg_send_bool! in favour of new functionality on msg_send! that allows seamlessly handling bool.
Added the "unstable-static-class" and "unstable-static-class-inlined"
feature flags to make the class! macro zero cost.
Moved the external crate objc2_foundation into objc2::foundation under
(default) feature flag "foundation".
Added declare_class!, extern_class! and ns_string! macros from
objc2-foundation.
Added helper method ClassBuilder::add_static_ivar.
BREAKING: Added ClassType trait, and moved the associated class
methods that extern_class! and declare_class! generated to that. This
means you'll have to use objc2::ClassType whenever you want to use e.g.
NSData::class().
Added Id::into_super.
Added extern_methods! macro.
Added ability to call msg_send![super(obj), ...] without explicitly
specifying the superclass.
Added automatic conversion of bool to/from the Objective-C BOOL in
msg_send!, msg_send_id!, extern_methods! and declare_class!.
Example:
// Before
use objc2::{msg_send, msg_send_bool};
use objc2::rc::{Id, Shared};
use objc2::runtime::{Bool, Object};
let obj: Id<Object, Shared>;
let _: () = unsafe { msg_send![&obj, setArg: Bool::YES] };
let is_equal = unsafe { msg_send_bool![&obj, isEqual: &*obj] };
// After
use objc2::msg_send;
use objc2::rc::{Id, Shared};
use objc2::runtime::Object;
let obj: Id<Object, Shared>;
let _: () = unsafe { msg_send![&obj, setArg: true] };
let is_equal: bool = unsafe { msg_send![&obj, isEqual: &*obj] };
BREAKING: Change syntax in extern_class! macro to be more Rust-like.
BREAKING: Change syntax in declare_class! macro to be more Rust-like.
BREAKING: Renamed Id::from_owned to Id::into_shared.
BREAKING: The return type of msg_send_id! is now more generic; it can
now either be Option<Id<_, _>> or Id<_, _> (if the latter, it'll panic
if the method returned NULL).
Example:
// Before
let obj: Id<Object, Shared> = unsafe {
msg_send_id![msg_send_id![class!(MyObject), alloc], init].unwrap()
};
// After
let obj: Id<Object, Shared> = unsafe {
msg_send_id![msg_send_id![class!(MyObject), alloc], init]
};
Updated ffi module to objc-sys v0.2.0-beta.2. This includes:
docs.rs setup.BREAKING: Updated encode module objc2-encode v2.0.0-pre.2.
In particular, Encoding no longer has a lifetime parameter:
// Before
#[repr(C)]
pub struct NSRange {
pub location: usize,
pub length: usize,
}
unsafe impl Encode for NSRange {
const ENCODING: Encoding<'static> = Encoding::Struct(
"_NSRange", // This is how the struct is defined in C header files
&[usize::ENCODING, usize::ENCODING]
);
}
unsafe impl RefEncode for NSRange {
const ENCODING_REF: Encoding<'static> = Encoding::Pointer(&Self::ENCODING);
}
// After
#[repr(C)]
pub struct NSRange {
pub location: usize,
pub length: usize,
}
unsafe impl Encode for NSRange {
const ENCODING: Encoding = Encoding::Struct(
"_NSRange", // This is how the struct is defined in C header files
&[usize::ENCODING, usize::ENCODING]
);
}
unsafe impl RefEncode for NSRange {
const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}
msg_send_bool! in favour of new functionality on msg_send!
that allows seamlessly handling bool.[0.3.0-beta.1]: https://github.com/madsmtm/objc2/compare/objc2-0.3.0-beta.0...objc2-0.3.0-beta.1
Added msg_send_id! to help with following Objective-C's memory management
rules. It is highly recommended that you use this instead of doing memory
management yourself!
Example:
// Before
let obj: Id<Object, Shared> = unsafe {
let obj: *mut Object = msg_send![class!(MyObject), alloc];
let obj: *mut Object = msg_send![obj, init];
Id::new(obj).unwrap()
};
// After
let obj: Id<Object, Shared> = unsafe {
msg_send_id![msg_send_id![class!(MyObject), alloc], init].unwrap()
};
Added the "unstable-static-sel" and "unstable-static-sel-inlined"
feature flags to make the sel! macro (and by extension, the msg_send!
macros) faster.
Added "unstable-c-unwind" feature.
Added unsafe function Id::cast for converting between different types of
objects.
Added Object::ivar_ptr to allow direct access to instance variables
through &Object.
Added VerificationError as more specific return type from
Class::verify_sel.
Added rc::Allocated struct which is used within msg_send_id!.
Added Class::responds_to.
Added exception::Exception object to improve error messages from caught
exceptions.
Added declare::Ivar<T> helper struct. This is useful for building safe
abstractions that access instance variables.
Added Id::from_owned helper function.
BREAKING: Sel is now required to be non-null, which means that you
have to ensure that any selectors you receive from method calls are
non-null before using them.
BREAKING: ClassBuilder::root is now generic over the function pointer,
meaning you will have to coerce initializer functions to pointers like in
ClassBuilder::add_method before you can use it.
BREAKING: Moved MessageReceiver::verify_message to Class::verify_sel
and changed return type.
Improved debug output with verify_message feature enabled.
BREAKING: Changed MessageReceiver::send_message to panic instead of
returning an error.
BREAKING: Renamed catch_all feature to catch-all.
BREAKING: Made passing the function pointer argument to
ClassBuilder::add_method, ClassBuilder::add_class_method and similar
more ergonomic.
Let's say you have the following code:
// Before
let init: extern "C" fn(&mut Object, Sel) -> *mut Object = init;
builder.add_method(sel!(init), init);
Unfortunately, you will now encounter a very confusing error:
|
2 | builder.add_method(sel!(init), init);
| ^^^^^^^^^^ implementation of `MethodImplementation` is not general enough
|
= note: `MethodImplementation` would have to be implemented for the type `for<'r> extern "C" fn(&'r mut Object, Sel) -> *mut Object`
= note: ...but `MethodImplementation` is actually implemented for the type `extern "C" fn(&'0 mut Object, Sel) -> *mut Object`, for some specific lifetime `'0`
To fix this, let the compiler infer the argument and return types:
// After
let init: extern "C" fn(_, _) -> _ = init;
builder.add_method(sel!(init), init);
Updated ffi module to objc-sys v0.2.0-beta.1. This includes:
unstable-c-unwind feature.doc_auto_cfg to improve documentation output.BREAKING: Updated encode module objc2-encode v2.0.0-pre.1.
nil exceptions in exception::throw.Sel::from_ptr method.MessageError.Properly sealed the MessageArguments trait (it already had a hidden method, so this is not really a breaking change).
Object::get_ivar and Object::get_mut_ivar to make
upgrading easier.From/TryFrom to convert between rc::Id and rc::WeakId.Bool::as_bool (more descriptive name than Bool::is_true).Id::as_ptr and Id::as_mut_ptr.objc2-encode dependency is now exposed as objc2::encode.Id::retain_autoreleased to allow following Cocoas memory management
rules more efficiently.msg_send!.msg_send_bool!, a less error-prone version of msg_send! for
Objective-C methods that return BOOL.MethodImplementation for unsafe function pointers.BREAKING: Changed signature of Id::new and Id::retain from
fn(NonNull<T>) -> Id<T> to fn(*mut T) -> Option<Id<T>>.
Concretely, you will have to change your code as follows.
// Before
let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] };
let obj = NonNull::new(obj).expect("failed to allocate object");
let obj = unsafe { Id::new(obj) };
// After
let obj: *mut Object = unsafe { msg_send![class!(NSObject), new] };
let obj = unsafe { Id::new(obj) }.expect("failed to allocate object");
Allow specifying any receiver T: Message for methods added with
ClassBuilder::add_method.
Renamed ClassDecl and ProtocolDecl to ClassBuilder and
ProtocolBuilder. The old names are kept as deprecated aliases.
BREAKING: Changed how msg_send! works wrt. capturing its arguments.
This will require changes to your code wherever you used Id, for example:
// Before
let obj: Id<Object, Owned> = ...;
let p: i32 = unsafe { msg_send![obj, parameter] };
let _: () = unsafe { msg_send![obj, setParameter: p + 1] };
// After
let mut obj: Id<Object, Owned> = ...;
let p: i32 = unsafe { msg_send![&obj, parameter] };
let _: () = unsafe { msg_send![&mut obj, setParameter: p + 1] };
Notice that we now clearly pass obj by reference, and therein also
communicate the mutability of the object (in the first case, immutable, and
in the second, mutable).
If you previously used *mut Object or &Object as the receiver, message
sending should work exactly as before.
BREAKING: Class no longer implements Message (but it can still be
used as the receiver in msg_send!, so this is unlikely to break anything
in practice).
BREAKING: Sealed the MethodImplementation trait, and made its imp
method privat.
BREAKING: Updated ffi module to objc-sys v0.2.0-beta.0. This includes:
links key from objc to objc_0_2 for better
future compatibility, until we reach 1.0 (so DEP_OBJC_CC_ARGS in build
scripts becomes DEP_OBJC_0_2_CC_ARGS).Class, Ivar, Method and Protocol
since they could be mistaken for the objc2::runtime structs with the same
name.objc_property_t.objc_hook_getClass and objc_hook_lazyClassNamer
type aliases (for now).DEP_OBJC_RUNTIME build script output.BREAKING: Updated objc2-encode (Encoding, Encode, RefEncode and
EncodeArguments) to v2.0.0-pre.0.
MessageArguments trait (it already had a hidden
method, so this is not really a breaking change).ManuallyDrop no longer implements Message directly.MessageReceiver::as_raw_receiver is no longer public.[0.3.0-alpha.6]: https://github.com/madsmtm/objc2/compare/objc2-0.3.0-alpha.5...objc2-0.3.0-alpha.6
Hash for Sel, Ivar, Class, Method and MessageError.PartialEq and Eq for Ivar, Method and MessageError.fmt::Pointer for Sel and rc::AutoreleasePool.fmt::Debug for ClassDecl, ProtocolDecl and rc::AutoreleasePool.Object::get_ivar -> Object::ivarObject::get_mut_ivar -> Object::ivar_mutffi module to objc-sys v0.2.0-alpha.1. This includes:
objc_exception_try_enter and objc_exception_try_exit on macOS x86.cfg-guarded the following types and methods to not
be available on macOS x86:
objc_exception_matcherobjc_exception_preprocessorobjc_uncaught_exception_handlerobjc_exception_handlerobjc_begin_catchobjc_end_catchobjc_exception_rethrowobjc_setExceptionMatcherobjc_setExceptionPreprocessorobjc_setUncaughtExceptionHandlerobjc_addExceptionHandlerobjc_removeExceptionHandlerobjc_set_apple_compatible_objcxx_exceptions since it
is only available when libobjc2 is compiled with the correct flags.object_setInstanceVariableWithStrongDefault since it
is only available since macOS 10.12.objc_setHook_getClass since it is only available
since macOS 10.14.4.objc_setHook_lazyClassNamer since it is only
available since macOS 11.docs.rs configuration.objc2-encode (Encoding, Encode, RefEncode and
EncodeArguments) to v2.0.0-beta.2.Deprecated runtime::BOOL, runtime::YES and runtime::NO. Use the newtype Bool instead, or low-level ffi::BOOL, ffi::YES and ffi::NO.
objc-sys as ffi module.rc::Owned and rc::Shared (useful in generic
contexts).RefEncode for runtime::Protocol.Message and MessageReceiver implementation for ManuallyDrop<T>
(where T is appropriately bound). This allows patterns like:let obj = Id::new(msg_send![class!(MyObject), alloc]);
let obj = ManuallyDrop::new(obj);
// `init` takes ownership and possibly returns a new object.
let obj = Id::new(msg_send![obj, init]);
"malloc", which allows cutting down on dependencies,
most crates don't need the introspection features that this provides.runtime::BOOL, runtime::YES and runtime::NO. Use the
newtype Bool instead, or low-level ffi::BOOL, ffi::YES and ffi::NO."malloc" feature
flag to be enabled:
MessageReceiver::verify_message (temporarily)Method::return_typeMethod::argument_typeClass::classesClass::instance_methodsClass::adopted_protocolsClass::instance_variablesProtocol::protocolsProtocol::adopted_protocolsSized bound on rc::Id and rc::WeakId to prepare for
extern type support.Sized bound on rc::SliceId and rc::DefaultId.objc-sys to v0.2.0-alpha.0. This includes:
NSInteger and NSUInteger (type aliases of isize/usize).NSIntegerMax, NSIntegerMin and NSUIntegerMax.cfg-guarded class_getImageName to only appear on
Apple platforms.!UnwindSafe.objc2-encode (Encoding, Encode, RefEncode and
EncodeArguments) to v2.0.0-beta.1.runtime module. These
are available in the new ffi module instead.rc methods.Class and Method) are now Send, Sync, UnwindSafe
and RefUnwindSafe again.
Notable exception is Object, because that depends on the specific
subclass.[0.3.0-alpha.4]: https://github.com/madsmtm/objc2/compare/objc2-0.3.0-alpha.3...objc2-0.3.0-alpha.4
Note: To use this version, specify objc2-encode = "=2.0.0-beta.0" in your
Cargo.toml as well.
objc-sys for the version they're using.objc_exception crate into exception module (under feature flag)._Complex types.rc::SliceId, rc::SliceIdMut and rc::DefaultId helper traits for
extra functionality on rc::Id.exception feature now only enables the exception
module, for general use. Use the new catch_all feature to wrap all message
sends in a @try/@catch.objc-sys to v0.1.0. This includes:
apple, gnustep-X-Y or winobjc to
specify the runtime you're using, instead of the RUNTIME_VERSION
environment variable.DEP_OBJC_RUNTIME now returns gnustep on WinObjC.objc2-encode (Encoding, Encode, RefEncode and
EncodeArguments) to v2.0.0-beta.0.[0.3.0-alpha.3]: https://github.com/madsmtm/objc2/compare/objc2-0.3.0-alpha.2...objc2-0.3.0-alpha.3
Note: To use this version, specify objc2-encode = "=2.0.0-alpha.1" in your
Cargo.toml as well.
objc-sys (v0.0.1) crate for possibly better
interoperability with other crates that link to libobjc.runtime::Bool to fix soundness issues with using
runtime::BOOL or bool.objc_id crate into rc module. Notable changes:
Id::autoreleaseId::from_sharedId for easier useId and WeakId are now able to use the null-pointer optimizationT: Message bounds on IdShareId type aliasId no longer have a default Ownership, you must specify
it everywhere as either Id<T, Shared> or Id<T, Owned>Ownership traitId::from_ptr to Id::retainId::from_retained_ptr to Id::newId::share to a From implementation (usage of
obj.share() can be changed to obj.into())Send and Sync bounds
on Id and WeakIdMessageReceiver to specify types that can
be used as the receiver of a message (instead of only allowing pointer
types).MessageReceiver::send_super_message method for dynamic selectors.runtime module.!UnwindSafe, to discourage trying to use
them after an unwind. This restriction may be lifted in the future.!Send and !Sync. This was an oversight
that is fixed in a later version.Message::send_message is moved
to MessageReceiver.MessageArguments a subtrait of EncodeArguments.msg_send!.rc::StrongPtr. Use Option<rc::Id<Object, Shared>>
instead (beware: This has stronger safety invariants!).rc::WeakPtr. Use rc::WeakId<Object> instead.msg_send!s first argument. The
MessageReceiver trait was introduced to avoid most breakage from this
change.[0.3.0-alpha.2]: https://github.com/madsmtm/objc2/compare/objc2-0.3.0-alpha.1...objc2-0.3.0-alpha.2
rc::AutoreleasePool and rc::AutoreleaseSafe to make accessing
autoreleased objects safe, by binding references to it using the
ptr_as_ref and ptr_as_mut methods.BREAKING: The closure in rc::autoreleasepool now takes an argument
&rc::AutoreleasePool. This reference can be given to functions like
INSString::as_str so that it knows which lifetime to bound the returned
&str with.
// Before
autoreleasepool(|| {
// Some code that autoreleases objects
});
// After
autoreleasepool(|_pool| {
// Some code that autoreleases objects
});
BOOL on GNUStep.[0.3.0-alpha.1]: https://github.com/madsmtm/objc2/compare/objc2-0.3.0-alpha.0...objc2-0.3.0-alpha.1
BREAKING: Change objc-encode dependency to objc2-encode version
2.0.0-alpha.1, and re-export the new RefEncode trait from that.
BREAKING: Require that the receiver, arguments and return types of
messages always implement Encode. This helps ensuring that only types made
to go across the FFI boundary (repr(C), ...) may. These requirements were
already present when the verify_message feature was enabled.
This is a very disruptive change, since libraries are now required to
implement Encode and RefEncode for all types intended to go across the
FFI-boundary to Objective-C. The change is justified because it helps
ensuring that users only pass valid types to msg_send! (for example, this
prevents users from accidentally passing Drop types to msg_send).
See the following examples for how to implement these traits, and otherwise
refer to the documentation of objc2-encode (v2.0.0-alpha.1 or above).
use objc2::{Encode, Encoding, RefEncode};
/// Example struct.
#[repr(C)]
pub struct NSRange {
pub location: usize,
pub length: usize,
}
unsafe impl Encode for NSRange {
const ENCODING: Encoding<'static> = Encoding::Struct(
"_NSRange", // This is how the struct is defined in C header files
&[usize::ENCODING, usize::ENCODING]
);
}
unsafe impl RefEncode for NSRange {
const ENCODING_REF: Encoding<'static> = Encoding::Pointer(&Self::ENCODING);
}
/// Example object.
#[repr(C)]
pub struct __CFString(c_void);
pub type CFStringRef = *const __CFString;
unsafe impl RefEncode for __CFString {
const ENCODING_REF: Encoding<'static> = Encoding::Object;
}
Temporarily disabled iOS tests.
objc_msgSend[_X] function to use based on the
Encode implementation of the return type. This fixes using functions that
return e.g. type CGFloat = f32 / f64;.[0.3.0-alpha.0]: https://github.com/madsmtm/objc2/compare/objc2-0.2.7...objc2-0.3.0-alpha.0
Note: This is the version that is, as of this writing, available on the
master branch in the original objc project.
// You can now do
use objc2::{sel, class, msg_send};
// Instead of
#[macro_use]
extern crate objc2;
BREAKING: Forked the project, so the crate name is now objc2.
BREAKING: Updated encoding utilities to use objc-encode. See that for
how to use the updated type Encoding and trait Encode.
In short, you will likely need to change your implementations of Encode
like this:
use objc2::{Encode, Encoding};
pub type CGFloat = ...; // Varies based on target_pointer_width
#[repr(C)]
pub struct NSPoint {
pub x: CGFloat,
pub y: CGFloat,
}
// Before
unsafe impl Encode for NSPoint {
fn encode() -> Encoding {
let encoding = format!(
"{{CGPoint={}{}}}",
CGFloat::encode().as_str(),
CGFloat::encode().as_str(),
);
unsafe { Encoding::from_str(&encoding) }
}
}
// After
unsafe impl Encode for NSPoint {
const ENCODING: Encoding<'static> = Encoding::Struct(
"CGPoint",
&[CGFloat::ENCODING, CGFloat::ENCODING]
);
}
BREAKING: Updated public dependency malloc_buf to 1.0.
BREAKING: Method::return_type and Method::argument_type now return
Malloc<str> instead of Encoding.
BREAKING: Ivar::type_encoding now return &str instead of Encoding.
sel_impl! macro.[0.2.7]: https://github.com/madsmtm/objc2/compare/objc2-0.2.6...objc2-0.2.7
msg_send! will now correctly fail to compile if no
return type can be inferred, instead of relying on an edge case of the
compiler that will soon change and silently cause undefined behavior.Your coding agent can read these notes before it upgrades. Set up the MCP server →