首页 > 解决方案 > ViewModel 获取新数据时视图未更新

问题描述

我有一个应用程序会每天调用一次 API 来检索新数据。

当应用程序启动时,它将检查新数据是否可用,将新数据保存到核心数据,调用核心数据以在视图中显示数据。

问题
将新数据保存到核心数据后,我的视图将不会显示新保存的数据,而是显示我模型中的默认虚拟数据。重新启动应用程序后将显示新数据。

问题
如何在视图中显示新保存的数据而无需重新启动应用程序?我正在使用 MVVM 模式。下面是我的代码,其中包含指向我的代码的链接。

UVIndexNow模型

class UVIndexNowModel: ObservableObject
{
    @Published var uvIndex: Int
    @Published var dateTime: Date
    
    init(uvIndex: Int = 0, dateTime: Date = Date())
    {
        self.uvIndex = uvIndex
        self.dateTime = dateTime
    }
}

UVIndexNowViewModel

class UVIndexNowViewModel: NSObject, ObservableObject
{
    private var isFirstAppearance = true
    private let moc = PersistentStore.shared.context
    private let nowController: NSFetchedResultsController<UVHour>
    
    @Published var data: UVIndexNowModel = UVIndexNowModel()
    @Published var coreDateError: Bool = false
    
    override init()
    {
        nowController = NSFetchedResultsController(fetchRequest: UVHour.uvIndexNowRequest,
                                                   managedObjectContext: moc,
                                                   sectionNameKeyPath: nil, cacheName: nil)
        
        super.init()
        
        nowController.delegate = self
        
        do {
            try nowController.performFetch()
            let results = nowController.fetchedObjects ?? []
            
            setUVIndex(from: results)
            
        } catch {
            print("failed to fetch items!")
        }
    }
    
    func setUVIndex(from hours: [UVHour])
    {
        let date = Date()
        let formatter = DateFormatter()
        formatter.timeZone = .current
        formatter.dateFormat = "MMM/d/yyyy hh a"

        let todaystr = formatter.string(from: date)
        
        print("UVIndexNowVM.setUVIndex() size of UVHour array: \(hours.count)")
        
        for i in hours
        {
            let tempDateStr = formatter.string(from: i.wrappedDateTime)

            if todaystr == tempDateStr
            {
                print("UV Now VM Date matches! \(tempDateStr)")
                
                self.data.uvIndex = i.wrappedUVIndex
                self.data.dateTime = i.wrappedDateTime
                break
            }
        }
    }
    
}

extension UVIndexNowViewModel: NSFetchedResultsControllerDelegate
{
    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
    {
        print("UVIndexNowViewModel controllerDidChangeContent was called. New Stuff in DB")
        guard let results = controller.fetchedObjects as? [UVHour] else { return }
        
        setUVIndex(from: results)
    }
}

UVIndexNowView

struct UVIndexNowView: View {
    @ObservedObject var vm = UVIndexNowViewModel()
    
    var body: some View {
        VStack {
            Text("\(vm.data.dateTime)")
            Text("UV Index: \(vm.data.uvIndex)")
        }
    }
}

标签: iosswiftcore-datamvvmswiftui

解决方案


作为您的UVIndexNowModelis-a ObservableObject,您需要在单独的视图中观察它,例如

struct UVIndexNowView: View {
    @ObservedObject var vm = UVIndexNowViewModel()
    
    var body: some View {
       UVIndexNowDataView(data: vm.data)    // << here !!
    }
}

struct UVIndexNowDataView: View {
    @ObservedObject var data: UVIndexNowModel
    
    var body: some View {
        VStack {
            Text("\(data.dateTime)")
            Text("UV Index: \(data.uvIndex)")
        }
    }
}

推荐阅读