【问题标题】:SwiftUI - onReceive not being called for an ObservableObject property change when the property is updated after view is loadedSwiftUI - 在加载视图后更新属性时,不会为 ObservableObject 属性更改调用 onReceive
【发布时间】:2020-07-06 00:03:59
【问题描述】:

我有一个视图,它以滚动视图显示从 API 加载的几张照片。我想推迟获取图像,直到显示视图。我的观点,简化看起来像这样:

struct DetailView : View {
    @ObservedObject var viewModel: DetailViewModel

    init(viewModel: DetailViewModel) {
        self.viewModel = viewModel
    }

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Color("peachLight").edgesIgnoringSafeArea(.all)
                if self.viewModel.errorMessage != nil {
                    ErrorView(error: self.viewModel.errorMessage!)
                } else if self.viewModel.imageUrls.count == 0 {
                    VStack {
                        Text("Loading").foregroundColor(Color("blueDark"))
                        Text("\(self.viewModel.imageUrls.count)").foregroundColor(Color("blueDark"))
                    }
                } else {
                    VStack {
                        UIScrollViewWrapper {
                            HStack {
                                ForEach(self.viewModel.imageUrls, id: \.self) { imageUrl in
                                    LoadableImage(url: imageUrl)
                                        .scaledToFill()
                                }.frame(width: geometry.size.width, height: self.scrollViewHeight)
                            }.edgesIgnoringSafeArea(.all)
                        }.frame(width: geometry.size.width, height: self.scrollViewHeight)
                        Spacer()
                    }
                }
            }
        }.onAppear(perform: { self.viewModel.fetchDetails() })
            .onReceive(viewModel.objectWillChange, perform: {
                print("Received new value from view model")
                print("\(self.viewModel.imageUrls)")
            })
    }
}

我的视图模型如下所示:

import Foundation
import Combine

class DetailViewModel : ObservableObject {
    @Published var imageUrls: [String] = []
    @Published var errorMessage : String?

    private var fetcher: Fetchable
    private var resourceId : String


    init(fetcher: Fetchable, resource: Resource) {
        self.resourceId = resource.id
        // self.fetchDetails() <-- uncommenting this line results in onReceive being called + a view update
    }


    // this is a stubbed version of my data fetch that performs the same way as my actual
    // data call in regards to ObservableObject updates

    // MARK - Data Fetching Stub
    func fetchDetails() {
        if let path = Bundle.main.path(forResource: "detail", ofType: "json") {
            do {
                let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
                let parsedData = try JSONDecoder().decode(DetailResponse.self, from: data)
                self.imageUrls = parsedData.photos // <-- this doesn't trigger a change, and even manually calling self.objectWillChange.send() here doesn't trigger onReceive/view update
                print("setting image urls to \(parsedData.photos)")

            } catch  {
                print("error decoding")
            }
        }
    }
}

如果我在视图模型的 init 方法中获取数据,则在设置 @Published imageUrls 属性时调用视图上的 onReceive 块。但是,当我从 init 方法中删除 fetch 并使用以下方法从视图中调用时:

 .onAppear(perform: { self.viewModel.fetchDetails() })

viewModel.objectWillChangeonReceive 不会被调用,即使数据已更新。我不知道为什么会这样,并且非常感谢这里的任何帮助。

【问题讨论】:

  • 您是如何创建 DetailViewModel 的(即在 SwiftUI 主体块中?)

标签: swiftui combine observableobject


【解决方案1】:

改为使用

.onReceive(viewModel.$imageUrls, perform: { newUrls in
    print("Received new value from view model")
    print("\(newUrls)")
})

【讨论】:

    【解决方案2】:

    我测试了这个,因为我发现了同样的问题,似乎只有值类型可以与 onReceive 一起使用

    使用枚举、字符串等

    它不适用于引用类型,因为我猜从技术上讲,引用类型不会更改引用位置,而只是在更改时指向其他地方? idk哈哈,但是你

    作为一种解决方案,您可以设置一个类似于状态枚举的 viewModel @published 属性,当您有新数据时对其进行更改,然后在接收时可以访问它...希望有道理,让我知道如果没有

    【讨论】:

      猜你喜欢
      • 2021-02-27
      • 2020-05-24
      • 1970-01-01
      • 1970-01-01
      • 2020-04-08
      • 2021-04-18
      • 2019-12-08
      • 2021-03-08
      • 2020-03-08
      相关资源
      最近更新 更多