rjk*_*lan 6 ios swift swiftui combine
我有一个SwiftUI视图,其中包含一个名为的EnvironmentObject appModel。然后,它读取appModel.submodel.count其body方法中的值。我希望这能将我的视图绑定到该属性count,submodel以便在属性更新时重新呈现该属性,但这似乎没有发生。
这是错误吗?如果不是,将视图绑定到SwiftUI中环境对象的嵌套属性的惯用方式是什么?
具体来说,我的模型看起来像这样...
class Submodel: ObservableObject {
@Published var count = 0
}
class AppModel: ObservableObject {
@Published var submodel: Submodel = Submodel()
}
Run Code Online (Sandbox Code Playgroud)
我的观点看起来像这样...
struct ContentView: View {
@EnvironmentObject var appModel: AppModel
var body: some View {
Text("Count: \(appModel.submodel.count)")
.onTapGesture {
self.appModel.submodel.count += 1
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行该应用程序并单击标签时,count属性会增加,但标签不会更新。
我可以通过将appModel.submodel属性作为传入来解决此问题ContentView,但如果可能的话,我想避免这样做。
Hie*_*ham 28
Sorin Lica 的解决方案可以解决这个问题,但是这会在处理复杂视图时导致代码异味。
似乎更好的建议是仔细审视你的观点,并修改它们以提出更多、更有针对性的观点。构造视图,以便每个视图显示对象结构的单个级别,将视图与符合ObservableObject. 在上面的情况下,您可以创建一个用于显示的视图Submodel(甚至多个视图),该视图显示您想要显示的属性。将属性元素传递给该视图,并让它为您跟踪发布者链。
struct ContentView: View {
@EnvironmentObject var appModel: AppModel
var body: some View {
SubView(submodel: appModel.submodel)
}
}
struct SubView: View {
@ObservedObject var submodel: Submodel
var body: some View {
Text("Count: \(submodel.count)")
.onTapGesture {
self.submodel.count += 1
}
}
}
Run Code Online (Sandbox Code Playgroud)
这种模式意味着制作更多、更小、更集中的视图,并让 SwiftUI 内部的引擎进行相关跟踪。这样您就不必处理簿记问题,而且您的观点也可能会变得更加简单。
您可以在这篇文章中查看更多详细信息:https://rhonabwy.com/2021/02/13/nested-observable-objects-in-swiftui/
hec*_*ckj 10
我最近在我的博客上写了相关内容:嵌套可观察对象。如果您确实想要 ObservableObjects 的层次结构,解决方案的要点是创建您自己的顶级组合主题以符合ObservableObject 协议,然后将您想要触发更新的任何逻辑封装到更新该内容的命令式代码中主题。
例如,如果您有两个“嵌套”类,例如
class MainThing : ObservableObject {
@Published var element : SomeElement
init(element : SomeElement) {
self.element = element
}
}
Run Code Online (Sandbox Code Playgroud)
class SomeElement : ObservableObject {
@Published var value : String
init(value : String) {
self.value = value
}
}
Run Code Online (Sandbox Code Playgroud)
然后您可以将顶级类(MainThing在本例中)扩展为:
class MainThing : ObservableObject {
@Published var element : SomeElement
var cancellable : AnyCancellable?
init(element : SomeElement) {
self.element = element
self.cancellable = self.element.$value.sink(
receiveValue: { [weak self] _ in
self?.objectWillChange.send()
}
)
}
}
Run Code Online (Sandbox Code Playgroud)
它从嵌入中获取发布者,并在修改类的ObservableObject属性时将更新发送到本地发布者中。您可以扩展它以使用CombineLatest从多个属性或主题的任意数量的变体发布流。valueSomeElement
但这不是一个“直接做”的解决方案,因为这种模式的逻辑结论是在您增长了视图层次结构之后,您最终将获得订阅该发布者的潜在大量视图样本将会失效并重绘,可能会导致过度的、全面的重绘和相对较差的更新性能。我建议您看看是否可以重构您的视图以使其特定于某个类,并将其与该类匹配,以最大限度地减少 SwiftUI 视图失效的“爆炸半径”。
如果您需要在此处嵌套可观察对象,这是我能找到的最佳方法。
class ChildModel: ObservableObject {
@Published
var count = 0
}
class ParentModel: ObservableObject {
@Published
private var childWillChange: Void = ()
let child = ChildModel()
init() {
child.objectWillChange.assign(to: &$childWillChange)
}
}
Run Code Online (Sandbox Code Playgroud)
您无需订阅子级的 objectWillChange 发布者并触发父级的发布者,而是自动为已发布的属性和父级的 objectWillChange 触发器分配值。
嵌套模型在SwiftUI中尚不可用,但是您可以执行以下操作
class Submodel: ObservableObject {
@Published var count = 0
}
class AppModel: ObservableObject {
@Published var submodel: Submodel = Submodel()
var anyCancellable: AnyCancellable? = nil
init() {
anyCancellable = submodel.objectWillChange.sink { (_) in
self.objectWillChange.send()
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,您可以AppModel捕获事件Submodel并将其发送到视图
编辑:
如果您不需要SubModel上课,则可以尝试以下方法:
struct Submodel{
var count = 0
}
class AppModel: ObservableObject {
@Published var submodel: Submodel = Submodel()
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
341 次 |
| 最近记录: |