跳转到内容
Skip 中文站
3.2k

SkipModel

为 Skip Lite 转译后的 Swift 提供模型对象观察能力。此包的一部分也由 Skip Fuse 使用,用于将 @Observables 桥接到 Compose。

在此处查看所包含的 API。

要在项目中包含此框架,请将以下依赖项添加到 Package.swift 文件:

let package = Package(
name: "my-package",
products: [
.library(name: "MyProduct", targets: ["MyTarget"]),
],
dependencies: [
.package(url: "https://source.skip.dev/skip-model.git", from: "1.0.0"),
],
targets: [
.target(name: "MyTarget", dependencies: [
.product(name: "SkipModel", package: "skip-model")
])
]
)

SkipModel 提供 skip.model Kotlin 包。该包包含 Observable 和 ObservableObject 接口,对应 SwiftUI 用于观察模型对象变化的两个核心协议;此外还提供有限的 Publisher 支持。

原文说明:SkipLib 依赖 skip ↗ 转译器插件和 SkipFoundation 包。

SkipModel 属于核心 SkipStack,并不建议直接导入。对于导入了 Combine、Observation 或 SwiftUI 框架的 Swift 源代码,转译器会在生成的 Kotlin 中加入 import skip.model.*。

对于 Observation 包,SkipModel 支持 @Observable 和 @ObservationIgnored 宏。

对于 Combine,SkipModel 支持 ObservableObject 协议、@Published 属性包装器,以及有限的 Publisher 功能。参见下方的 API 支持。

Skip 的大部分模型支持直接实现在 Skip 转译器中。Observable 和 ObservableObject 标记协议足以让 Skip 转译器识别可观察类型。生成对应的 Kotlin 类时,转译器会加入必要代码,使其状态可由 Compose 运行时跟踪。

欢迎为 SkipModel 贡献代码。Skip 产品的文档包含本地开发 Skip 库时很有帮助的说明与技巧。提交代码时,请在 PR ↗ 中包含单元测试。

与 Skip 本身一样,SkipModel 对象也是双平台的!@Observable 和 ObservableObject 属性不仅会参与 SwiftUI 的状态跟踪,也会由 Compose 跟踪。Skip 转译器在 Kotlin 中使用 MutableState 值作为可观察属性的底层支持,因此 Compose 会自动跟踪读写,并按需执行重组 ↗。

这意味着,你可以使用可观察对象编写共享的模型层 Swift 代码,并让它同时驱动 SwiftUI(无论仅用于 iOS,还是通过 Skip 实现双平台)和纯 Android Compose UI 代码。例如,下面这个模型类:

@Observable class TapCounter {
var tapCount = 0
}

可以驱动如下 Compose UI:

val tapCounter = TapCounter()
...
TapIt(counter = tapCounter)
...
@Composable fun TapIt(counter: TapCounter) {
Button(onClick = { counter.tapCount += 1 }) {
Text("Tap Count: ${counter.tapCount}")
}
}

下表汇总了 SkipModel 在 Android 上的 API 支持情况。未列出的内容很可能尚不受支持。请注意,在仅用于 iOS 的代码中(即 #if !SKIP 代码块内),你可以使用任意 Swift API。此外:

  • 在所有 Combine 发布器及相关 API 中,Failure 类型必须为 Never:不支持在 Combine 链中抛出错误。
  • 在 Skip 中,执行 import Foundation 时不会自动导入 Combine。请务必显式执行 import Combine 或 import SwiftUI。

支持级别:

  • ✅ – 完整支持
  • 🟢 – 高度支持
  • 🟡 – 中等支持
  • 🟠 – 少量支持
支持度API
🟢
AnyCancellable
  • 参见 Cancellable
🟠
AnyPublisher
  • init(_ publisher: Publisher)
  • 参见 Publisher
🟢
Cancellable
  • store(in:) 函数仅支持 Set
🟠
ConnectablePublisher
  • func connect()
  • func autoconnect()
  • 参见 Publisher
✅ func NotificationCenter.publisher(for: Notification.Name, object: Any? = nil): Publisher<Notification, Never>
🟢
@Observable
  • Skip 不支持调用生成的 access(keyPath:) 和 withMutation(keyPath:_:) 函数
🟢
ObservableObject
  • 如果自行声明 objectWillChange 发布器,其类型必须为 ObservableObjectPublisher
🟠
ObservableObjectPublisher
  • func send()
  • 参见 Publisher
✅ @ObservationIgnored
🟠
PassthroughSubject
  • func send(value: Output)
  • 参见 Publisher
✅ @Published
🟠
Publisher
  • func assign<Root>(to: KeyPath<Root, Output>, on: Root) -> AnyCancellable
  • func sink(receiveValue: (Output) -> Unit) -> AnyCancellable
  • func combineLatest(_ with: Publisher) -> Publisher
  • func combineLatest3(_ with0: Publisher, _ with1: Publisher) -> Publisher
  • func combineLatest4(_ with0: Publisher, _ with1: Publisher, _ with2: Publisher) -> Publisher
  • func debounce(for: Double, scheduler: Scheduler) -> Publisher
  • func dropFirst(count: Int = 1) -> Publisher
  • func filter(isIncluded: (Output) -> Boolean) -> Publisher
  • func map<T>(transform: (Output) -> T) -> Publisher
  • func receive(on: Scheduler): Publisher
  • func eraseToAnyPublisher(): AnyPublisher
✅ func Timer.publish(every: TimeInterval, tolerance: TimeInterval? = nil, on runLoop: RunLoop, in mode: RunLoop.Mode, options: RunLoop.SchedulerOptions? = nil) -> ConnectablePublisher<Date, Never>

skiptools/skip-model ↗ 最近发布的 10 个版本:

完整历史记录: github.com/skiptools/skip-model/releases ↗ — .atom 订阅源 ↗