SwiftUI 合并零数据

SwiftUI combine nil data

我创建了一个 class 来执行网络请求并使用 Combine 解析数据。我完全确定代码是正确的但它现在正在工作(仍在学习 Swift 和基本网络任务的基础知识)。我的 Widget 具有正确的数据,并且在数据变为零之前一直有效。不确定如何检查我的 SwiftUI View 中第一个 publisher 的数据是否为零,即使没有游戏显示,数据似乎也是有效的。

我的SwiftUI查看

struct SimpleEntry: TimelineEntry {
    let date: Date
    public var model: CombineData?
    let configuration: ConfigurationIntent
}

struct Some_WidgetEntryView : View {
    var entry: Provider.Entry
    @Environment(\.widgetFamily) var widgetFamily
    
    var body: some View {
        VStack (spacing: 0){
            if entry.model?.schedule?.dates.first?.games == nil {
                Text("No games Scheduled")
            } else {
                Text("Game is scheduled")
            }
        }
    }
}

合并

import Foundation
import WidgetKit
import Combine

// MARK: - Combine Attempt
class CombineData {
    var schedule: Schedule?
    var live: Live?
    
    private var cancellables = Set<AnyCancellable>()
    
    func fetchSchedule(_ teamID: Int, _ completion: @escaping (Live) -> Void) {
        let url = URL(string: "https://statsapi.web.nhl.com/api/v1/schedule?teamId=\(teamID)")!
        let publisher = URLSession.shared.dataTaskPublisher(for: url)
            .map(\.data)
            .decode(type: Schedule.self, decoder: JSONDecoder())
            //.catch { _ in Empty<Schedule, Error>() }
            //.replaceError(with: Schedule(dates: []))
        let publisher2 = publisher
            .flatMap {
                return self.fetchLiveFeed([=11=].dates.first?.games.first?.link ?? "")
            }
        Publishers.Zip(publisher, publisher2)
            .receive(on: DispatchQueue.main)
            .sink(receiveCompletion: {_ in
            }, receiveValue: { schedule, live in
                self.schedule = schedule
                self.live = live
                completion(self.live!)
                WidgetCenter.shared.reloadTimelines(ofKind: "NHL_Widget")
            }).store(in: &cancellables)
    }

    func fetchLiveFeed(_ link: String) -> AnyPublisher<Live, Error /*Never if .catch error */> {
        let url = URL(string: "https://statsapi.web.nhl.com\(link)")!
        return URLSession.shared.dataTaskPublisher(for: url)
            .map(\.data)
            .decode(type: Live.self, decoder: JSONDecoder())
            //.catch { _ in Empty<Live, Never>() }
            .eraseToAnyPublisher()
    }
}

就像我在评论中所说的那样,decode(type: Live.self, decoder: JSONDecoder()) return 很可能是一个错误,因为当 link 时您正在获取的 URL 是 nil 没有 return 任何可以解码为 Live.self.

的东西

所以你需要以某种方式处理这种情况。例如,您可以通过使 Live 变量成为可选变量,并在 link 为空(或 nil)时 returning nil 来处理此问题。

这只是为了让您朝着正确的方向前进 - 您需要自己制定确切的代码。

let publisher2 = publisher1
   .flatMap {
       self.fetchLiveFeed([=10=].dates.first?.games.first?.link ?? "")
          .map { [=10=] as Live? } // convert to an optional
          .replaceError(with: nil)
   }

然后在sink中处理nil:

.sink(receiveCompletion: {_ in }, receiveValue: 
      { schedule, live in
          if let live = live {
              // normal treatment
             self.schedule = schedule 
             self.live = live
             //.. etc
          } else {
              // set a placeholder
          }
      })

SwiftUIWidgetKit 的工作方式不同。我需要在 getTimeline 中为我的 IntentTimelineProvider 获取数据,然后为我的 TimelineEntry 添加一个 completion 处理程序。大量修改了我的 Combine 数据模型。所有功劳归于 @EmilioPelaez for pointing me in the right direction, .