首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当使用ForEach更改数据时,视图不会更新。

当使用ForEach更改数据时,视图不会更新。
EN

Stack Overflow用户
提问于 2022-04-29 08:06:16
回答 2查看 60关注 0票数 -1

我想更改速率参数并在ForEach中显示。

代码语言:javascript
复制
// ViewModel.swift

@MainActor final class ViewModel: ObservableObject {
    let serviceContainer: ServiceContainerProtocol

    @Published var funds: [FundModel] = []
    ...

    init(serviceContainer: ServiceContainerProtocol) {
        self.serviceContainer = serviceContainer

        Task { await getFunds() }
        ...
    }

    ...
}
代码语言:javascript
复制
// FundView.swift

struct FundView: View {
    @StateObject private var viewModel: ViewModel

    init(serviceContainer: ServiceContainerProtocol) {
        self._viewModel = StateObject(wrappedValue: ViewModel(serviceContainer: serviceContainer))
    }

    var body: some View {
        ScrollView { 
            VStack {
                ForEach(viewModel.funds, id: \.fundCode) { fund in
                    VStack {
                        Text(String(fund.rate))

                        Button("Add 5") {
                            if let index = viewModel.funds.firstIndex(where: { $0.fundCode == fund.fundCode }) {
                                viewModel.funds[index].rate += 5
                            }
                        }
                    }
                }
            }
        }
    }
}

如果我使用Struct作为模型,视图按预期进行了更新。

代码语言:javascript
复制
// FundModel.swift

struct FundModel: Decodable {
    let fundCode: String
    ...

    // Internal - Not related to api.
    var rate: Int = 0
    ...

    // MARK: CodingKeys

    private enum CodingKeys: String, CodingKey {
        case fundCode
        ...
    }

    // MARK: Decodable

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        fundCode = try container.decode(String.self, forKey: .fundCode)
        ...
    }
}

如果我使用类作为模型,视图没有更新。

代码语言:javascript
复制
// FundModel.swift

final class FundModel: Decodable {
    let fundCode: String
    ...

    // Internal - Not related to api.
    var rate: Int = 0
    ...

    // MARK: CodingKeys

    private enum CodingKeys: String, CodingKey {
        case fundCode
        ...
    }

    // MARK: Decodable

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        fundCode = try container.decode(String.self, forKey: .fundCode)
        ...
    }
}

我想使用Class作为模型,因为它需要从某些超级类继承一些属性。

对于SwiftUI透视图来说,Struct模型和类模型有什么区别,为什么当我使用类模型而不是Struct模型时,视图没有更新?

注意: FundModel在其他地方符合Equtable和Hashable。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-04-29 08:40:17

使用class ViewModel: ObservableObject {...} (没有@MainActor)和viewModel.objectWillChange.send()来尝试这种方法,如下面的示例代码所示:

代码语言:javascript
复制
 struct FundView: View {
    @StateObject private var viewModel: ViewModel

    init(serviceContainer: ServiceContainerProtocol) {
        self._viewModel = StateObject(wrappedValue: ViewModel(serviceContainer: serviceContainer))
    }

    var body: some View {
        ScrollView {
            VStack {
                ForEach(viewModel.funds, id: \.fundCode) { fund in
                    VStack {
                        Text(String(fund.rate))

                        Button("Add 5") {
                            if let index = viewModel.funds.firstIndex(where: { $0.fundCode == fund.fundCode }) {
                                viewModel.objectWillChange.send() // <-- here
                                viewModel.funds[index].rate += 5
                            }
                        }
                    }
                }
            }
        }
    }
}

final class FundModel: Decodable {
    let fundCode: String
    var rate: Int = 0

   //....
}
票数 0
EN

Stack Overflow用户

发布于 2022-04-29 08:23:25

@Published var更改时,视图将更新。您的@Published var是一个FundModel数组。

结构不是可变的实体,所以当您使用struct时,数组实际上将对象替换为一个新的对象。系统识别数组中的更改并将其发布到视图中。

类是可变的,所以当您更改类内的速率时,仍然有相同的实例。因此,FundModel的数组不会改变:它仍然包含完全相同的元素,即使其中一个元素已经更改了一个内部变量。

@Published包装器无法检测数组成员的内部变量是否已更改:它只检测数组内部有不同元素的情况。

结论:struct需要创造一个新的元素来改变,@Published认识到了这一点。class可以更改,因此对于@Published,对象仍然是相同的(数组没有改变)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72054710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档