22 个版本

0.5.2 2024 年 5 月 21 日
0.5.0 2023 年 12 月 3 日
0.4.1 2023 年 7 月 31 日
0.3.0-beta.52023 年 2 月 7 日
0.3.0-alpha.42021 年 11 月 22 日

macOS 和 iOS API 中排名第 13

Download history 79134/week @ 2024-05-03 84867/week @ 2024-05-10 94138/week @ 2024-05-17 103607/week @ 2024-05-24 115489/week @ 2024-05-31 117514/week @ 2024-06-07 122366/week @ 2024-06-14 131268/week @ 2024-06-21 126927/week @ 2024-06-28 113629/week @ 2024-07-05 123549/week @ 2024-07-12 115332/week @ 2024-07-19 118866/week @ 2024-07-26 107274/week @ 2024-08-02 114956/week @ 2024-08-09 90517/week @ 2024-08-16

每月下载量 452,816
1,838 个crate (126 个直接使用) 中使用

MIT 许可证

1MB
15K SLoC

objc2

Latest version License Documentation CI

Rust 中的 Objective-C 接口和运行时绑定。

大多数在 Apple 系统上使用的核心库和框架都是用 Objective-C 编写的;这个crate使您能够与之交互。

这个 README 故意保持较小,以便于整合文档,更多信息请参阅 Rust 文档

这个crate是objc2项目的一部分,有关相关crate的信息请参阅该项目。


lib.rs:

Objective-C 接口和运行时绑定

快速链接

Objective-C 曾经是 macOS、iOS、iPadOS、tvOS 和 watchOS 等Apple平台的标准编程语言。它是一种以“向实例发送消息”为中心的面向对象语言——这可以大部分被视为函数调用。

它已经被 Swift 取代,但大多数在 Apple 系统上使用的核心库和框架仍然是用 Objective-C 编写的,因此我们希望能够使用 Rust 与这些库进行交互。这个crate使您能够以尽可能安全的方式做到这一点。

基本用法

此示例演示了此crate中的主要功能部分

首先,我们使用 ClassType::alloc 分配一个新的 NSObject。接下来,我们初始化这个对象。它确保使用 rc::Retained 来释放它。现在我们可以自由地向对象发送我们想要的消息,使用 msg_send!msg_send_id! 宏(取决于方法的返回类型)。最后,当 Retained 超出作用域时,对象将被释放并销毁。

use objc2::{msg_send, msg_send_id, ClassType};
use objc2::ffi::NSUInteger;
use objc2::rc::Retained;
use objc2::runtime::{NSObject, NSObjectProtocol};

// Creation

let obj1: Retained<NSObject> = unsafe {
    msg_send_id![NSObject::alloc(), init]
};
// Or
let obj2 = NSObject::new();

// Usage

let hash1: NSUInteger = unsafe { msg_send![&obj1, hash] };
let hash2: NSUInteger = unsafe { msg_send![&obj2, hash] };
assert_ne!(hash1, hash2);

let is_kind: bool = unsafe {
    msg_send![&obj1, isKindOfClass: NSObject::class()]
};
assert!(is_kind);

let obj1_self: Retained<NSObject> = unsafe { msg_send_id![&obj1, self] };
assert_eq!(obj1, obj1_self);

// Deallocation on drop

注意,这个例子包含很多 unsafe(理想情况下都应该用 // SAFETY 注释来证明)。这是必需的,因为我们的编译器几乎无法验证 Objective-C 调用,包括 msg_send! 中使用的所有参数和返回类型。我们可能不小心将 hash 的返回类型改为 f32 或其他任何类型,这将触发未定义的行为!

有关如何更方便地使用类似 FoundationAppKitUIKit 等系统框架的示例,请参阅 框架存储库

无论如何,所有这些 unsafe 都很好地引出了这个存储库的另一个功能

编码和消息类型验证

Objective-C 运行时为每个方法包含编码,描述了参数和返回类型。有关此内容的全面概述,请参阅 encode 模块。

重要的是:为了使消息发送更安全,所有消息的参数和返回值都必须实现 encode::Encode。这允许 Rust 编译器防止你将例如 Vec 传递给 Objective-C,这将既是不确定的,又会泄露向量。

此外,我们可以利用运行时提供的编码来验证 Rust 中使用的类型实际上与为该方法编码的类型匹配。这并不是确保安全性的完美解决方案(一些 Rust 类型具有相同的 Objective-C 编码,但不是等价的,例如 &T*const T),但它让我们更接近它!

当启用 debug_assertions 时,我们会在每次发送消息时检查编码,如果它们不匹配,消息发送将引发恐慌。

以上面的例子为例,如果我们更改 hash 方法的返回类型,如下所示,如果启用调试断言,它将引发恐慌

#
#
// Wrong return type - this is UB!
let hash1: f32 = unsafe { msg_send![&obj1, hash] };
#

这个库包含更多此类调试检查。

存储库功能

这个存储库导出了一些可选的 cargo 功能,请参阅 Cargo.toml 以了解概述和描述。

对其他操作系统的支持

这些绑定可以在使用 GNUstep Objective-C 运行时 的 Linux 或 *BSD 上使用,请参阅 objc-sys 存储库了解如何配置。

其他功能

这是一次简短的介绍,这个库还支持异常处理、[声明Objective-C类][declare_class!]、高级引用计数工具等更多功能——请随意查阅文档!

依赖项