swiftui - SwiftUI 和组合
问题描述
我正在关注Firebase YouTube 频道上的视频。大约从 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
东西是怎么回事?(它的定义与.private var cancellables = Set<AnyCancellable>()
之前一样init{}
。)第三,为什么所有这些代码,而不仅仅是:
task.completionStateIconName = task.isCompleted ? "checkmark.circle.fill" : "circle"
这似乎给出了相同的结果,但是第一个代码片段有效,而第二个无效?
解决方案
$task
(带有$
前缀)是@Published
属性包装器的投影值,它返回类型为 的变量Published.Publisher
。换句话说,它是一个组合发布者,它在属性(在这种情况下Task
)发生变化时发布一个值。
如果您没有了解 Combine 框架(或其他响应式框架),那么这个答案肯定是不够的。在高层次上,Combine 发布者发出值,您可以通过诸如 之类的运算符对其进行转换.map
,并最终订阅,例如使用.sink
or .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)
现在,上面返回一个 的实例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"
}
}
推荐阅读
- java - JPA Query Spring 的异常
- paypal - 找不到“付款前创建”方法(OctoberCms 的 Lovata Paypal Shopaholic 插件)
- python - 从 PCollection 中提取常量值
- c++ - 在 C++ 中填充缓冲区
- java - 带有 AWS EC2 测试容器的 moto-server docker 映像
- c++ - 从父类调用派生成员函数
- c++ - 预编译期间未连接模块。C++20
- html - 屏幕高度后的css布局页脚
- vb.net - 如何回到 Visual Studio 中的表单设计器
- python - 按下键时如何退出while循环?