SwiftUI 和组合
SwiftUI and Combine
我正在关注 video on the Firebase YouTube channel。从 27:45 左右开始,讲师试图根据布尔值设置一个变量,并以 init(task: Task)
中的以下代码结束:
$task
.map { task in
task.isCompleted ? "checkmark.circle.fill" : "circle"
}
.assign(to: \.completionStateIconName, on: self)
.store(in: &cancellables)
这对我来说似乎过于复杂。首先,我找不到关于在结构对象上使用 .map
的文档,只能在数组等上使用。其次,这个 &cancellables
是什么东西? (它在 init{}
之前被定义为 private var cancellables = Set<AnyCancellable>()
。)第三,为什么所有这些代码,而不是简单的:
task.completionStateIconName = task.isCompleted ? "checkmark.circle.fill" : "circle"
这似乎给出了相同的结果,但是否会出现第一个代码片段有效而第二个代码片段无效的情况?
$task
(带有 $
前缀)是 @Published
属性 包装器的投影值,它 returns 类型的变量Published.Publisher
。换句话说,它是一个 Combine 发布者,它会在 属性 - 在本例中 Task
- 发生变化时发布一个值。
如果您没有了解 Combine 框架(或其他响应式框架),这个答案肯定是不够的。在较高级别,Combine 发布者发出值,您可以通过 .map
等运算符转换这些值,并最终订阅,例如 .sink
或 .assign
.
所以,逐行:
// a publisher of Task values
$task
// next, transform Task into a String using its isCompleted property
.map { task in
task.isCompleted ? "circle.fill" : "circle"
}
// subscribe, by assigning the String value to the completionStateIconName prop
.assign(to: \.completionStateIconName, on: self)
现在,上面的 returns 是 AnyCancellable
的一个实例,您需要在接收值时保留它。因此,您要么需要将其直接存储为 属性,要么使用 .store
将其添加到 Set<AnyCancellable>
- 一种常见的方法。
那么,为什么这么复杂呢?据推测,这是为了在 task
属性 发生变化时,Combine 管道将更新 completionStateIconName
属性.
如果你刚刚做了:
completionStateIconName = task.isCompleted ? "circle.fill" : "circle"
那会在一开始就赋值。
话虽如此,在这种特殊情况下,使用 Combine 实际上可能过于复杂,而仅使用 didSet
:
var task: Task {
didSet {
completionStateIconName ? task.isCompleted ? "circle.fill" : "circle"
}
}
我正在关注 video on the Firebase YouTube channel。从 27:45 左右开始,讲师试图根据布尔值设置一个变量,并以 init(task: Task)
中的以下代码结束:
$task
.map { task in
task.isCompleted ? "checkmark.circle.fill" : "circle"
}
.assign(to: \.completionStateIconName, on: self)
.store(in: &cancellables)
这对我来说似乎过于复杂。首先,我找不到关于在结构对象上使用 .map
的文档,只能在数组等上使用。其次,这个 &cancellables
是什么东西? (它在 init{}
之前被定义为 private var cancellables = Set<AnyCancellable>()
。)第三,为什么所有这些代码,而不是简单的:
task.completionStateIconName = task.isCompleted ? "checkmark.circle.fill" : "circle"
这似乎给出了相同的结果,但是否会出现第一个代码片段有效而第二个代码片段无效的情况?
$task
(带有 $
前缀)是 @Published
属性 包装器的投影值,它 returns 类型的变量Published.Publisher
。换句话说,它是一个 Combine 发布者,它会在 属性 - 在本例中 Task
- 发生变化时发布一个值。
如果您没有了解 Combine 框架(或其他响应式框架),这个答案肯定是不够的。在较高级别,Combine 发布者发出值,您可以通过 .map
等运算符转换这些值,并最终订阅,例如 .sink
或 .assign
.
所以,逐行:
// a publisher of Task values
$task
// next, transform Task into a String using its isCompleted property
.map { task in
task.isCompleted ? "circle.fill" : "circle"
}
// subscribe, by assigning the String value to the completionStateIconName prop
.assign(to: \.completionStateIconName, on: self)
现在,上面的 returns 是 AnyCancellable
的一个实例,您需要在接收值时保留它。因此,您要么需要将其直接存储为 属性,要么使用 .store
将其添加到 Set<AnyCancellable>
- 一种常见的方法。
那么,为什么这么复杂呢?据推测,这是为了在 task
属性 发生变化时,Combine 管道将更新 completionStateIconName
属性.
如果你刚刚做了:
completionStateIconName = task.isCompleted ? "circle.fill" : "circle"
那会在一开始就赋值。
话虽如此,在这种特殊情况下,使用 Combine 实际上可能过于复杂,而仅使用 didSet
:
var task: Task {
didSet {
completionStateIconName ? task.isCompleted ? "circle.fill" : "circle"
}
}