更新属性包装器,例如@StateObject,会影响不使用该属性的其他视图渲染

发布于 2025-02-12 14:05:54 字数 2583 浏览 1 评论 0原文

当使用与视图更新关联的不同属性包装器时,一个位置的更改会影响不使用该属性的视图的渲染。

struct ContentView: View {

    @StateObject var viewModel = MyViewModel()
    @State var thirdTitle = "thirdTitle"

    var body: some View {
        VStack {
            Text(viewModel.firstTitle)
                .background(.random)
            Text(viewModel.secondTitle)
                .background(.random)
            Text(thirdTitle)
                .background(.random)

            Button("Change First Title") {
                viewModel.chageFirstTitle()
            }
        }
    }
}

class MyViewModel: ObservableObject {
    
    @Published var firstTitle = "firstTitle"
    @Published var secondTitle = "secondTitle"
    
    func chageFirstTitle() {
        firstTitle = "hello world"
    }
}

我了解text公开viewModel.secondtitle重新渲染是因为@StateObject varviewModel = myViewModel()依赖关系在更改`viewModel.firsttitle时更改。

但是,我不知道为什么文本使用@State var trixtitle =“ thixttitle”也被重新渲染。在wwdc21 session demystife swiftui ,我看到了该视图仅在根据依赖关系图更新相关的依赖项时重新渲染。但是,即使thixtetle与更改viewmodel的更改无关改变了。

更令人困惑的是,如果我将第三个文本分开为单独的视图(thirdview),然后使用@binding接收thixttitle,背景颜色不会更改,因为当时它没有重新渲染。

struct ContentView: View {

    @StateObject var viewModel = MyViewModel()
    @State var thirdTitle = "thirdTitle"

    var body: some View {
        VStack {
            Text(viewModel.firstTitle)
                .background(.random)
            Text(viewModel.secondTitle)
                .background(.random)
            ThirdView(text: $thirdTitle)
                .background(.random)

            Button("Change First Title") {
                viewModel.chageFirstTitle()
            }
        }
    }
}

struct ThirdView: View {
    
    @Binding var text: String
    
    var body: some View {
        Text(text)
            .background(.random)
    }
}

关于我解释的情况,您能帮我了解视图的渲染条件吗?

When using different property wrappers associated with view updates, changes in one place affect rendering of views that do not use that property.

enter image description here

struct ContentView: View {

    @StateObject var viewModel = MyViewModel()
    @State var thirdTitle = "thirdTitle"

    var body: some View {
        VStack {
            Text(viewModel.firstTitle)
                .background(.random)
            Text(viewModel.secondTitle)
                .background(.random)
            Text(thirdTitle)
                .background(.random)

            Button("Change First Title") {
                viewModel.chageFirstTitle()
            }
        }
    }
}

class MyViewModel: ObservableObject {
    
    @Published var firstTitle = "firstTitle"
    @Published var secondTitle = "secondTitle"
    
    func chageFirstTitle() {
        firstTitle = "hello world"
    }
}

I understand that the reason why the Text exposing the viewModel.secondTitle is re-rendered is because the @StateObject varviewModel = MyViewModel() dependency changed when the `viewModel.firstTitle changed.

However, I don't know why Text using @State var thirdTitle = "thirdTitle" is re-rendered too. In WWDC21 session Demystify SwiftUI, I saw that the view is re-rendered only when the related dependency is updated according to the dependency graph. But, even though the thirdTitle is irrelevant to the change of the viewModel, third Text using that dependency is re-rendered and the background color is changed.

What's even more confusing is that if I seperate the third Text into a separate view ( ThirdView ) and receive the thirdTitle using @Binding, the background color does not change because it is not re-rendering at that time.

struct ContentView: View {

    @StateObject var viewModel = MyViewModel()
    @State var thirdTitle = "thirdTitle"

    var body: some View {
        VStack {
            Text(viewModel.firstTitle)
                .background(.random)
            Text(viewModel.secondTitle)
                .background(.random)
            ThirdView(text: $thirdTitle)
                .background(.random)

            Button("Change First Title") {
                viewModel.chageFirstTitle()
            }
        }
    }
}

struct ThirdView: View {
    
    @Binding var text: String
    
    var body: some View {
        Text(text)
            .background(.random)
    }
}

enter image description here

Regarding the situation I explained, could you help me to understand the rendering conditions of the view?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

往事风中埋 2025-02-19 14:05:54

要渲染swiftui调用body视图的属性(它是可计算的,即在呼叫上完全执行)。每当更改任何视图依赖项(即动态属性)时,都会执行此调用。

因此,viewModel.ChageFirstTitle()更改contentViewcontent> contentview.body的依赖关系,并呈现其中的每个原始性。 也创建了,但就其依赖关系而言而言,其body未调用,因此不重新渲染内容。

To render SwiftUI calls body property of a view (it is computable, i.e. executes completely on call). This call is performed whenever any view dependency, i.e. dynamic property, is changed.

So, viewModel.chageFirstTitle() changes dependency for ContentView and ContentView.body is called and every primitive in it is rendered. ThirdView also created but as far as its dependency is not changed, its body is not called, so content is not re-rendered.

[旋木] 2025-02-19 14:05:54

这里有一些错误。我们不会在SwiftUI中使用查看模型对象进行查看数据,这样做是相当低效率的/错误的。相反,将带有@State突变弹性的结构使用。将参数传递给子视图,作为让读取访问的让@binding仅在您需要写入访问时才是。在渲染方面,首先仅在 的情况然后有任何差异,然后SwiftUi代表您添加/删除/更新实际的Uikit Uiviews,然后由这些Uiview的实际渲染,例如drawRect,由Coregraphics。

struct ContentViewConfig {
    
    var firstTitle = "firstTitle"
    var secondTitle = "secondTitle"
    
    mutating func changeFirstTitle() {
        firstTitle = "hello world"
    }
}

struct ContentView: View {
    @State var config = Config()
    ...

struct ThirdView: View {
    let text: String
    ...

Combine的observableObject通常仅在需要使用组合时使用,例如使用combineLatest与多个发布者或用于store> Store对象保持模型结构阵列在@published属性中,这些属性与视图的寿命没有@state。您的用例看起来不像observableObject的有效用途。

A few things wrong here. We don't use view model objects in SwiftUI for view data, it's quite inefficient/buggy to do so. Instead, use a struct with mutating funcs with an @State. Pass in params to sub-Views as lets for read access, @Binding is only when you need write access. In terms of rendering, first of all body is only called if the let property is different from the last time the sub-View is init, then it diffs the body from the last time it was called, if there are any differences then SwiftUI adds/removes/updates actual UIKit UIViews on your behalf, then actual rendering of those UIViews, e.g. drawRect, is done by CoreGraphics.

struct ContentViewConfig {
    
    var firstTitle = "firstTitle"
    var secondTitle = "secondTitle"
    
    mutating func changeFirstTitle() {
        firstTitle = "hello world"
    }
}

struct ContentView: View {
    @State var config = Config()
    ...

struct ThirdView: View {
    let text: String
    ...

Combine's ObservableObject is usually only used when needing to use Combine, e.g. using combineLatest with multiple publishers or for a Store object to hold the model struct arrays in @Published properties that are not tied to a View's lifetime like @State. Your use case doesn't look like a valid use of ObservableObject.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文