0

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

我的 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($0.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()
    }
}
4

2 回答 2

0

SwiftUIWidgetKit以不同的方式工作。我需要为我获取数据,getTimeline然后IntentTimelineProvidercompletion我的TimelineEntry. 大量修改了我的Combine数据模型。所有功劳归于@EmilioPelaez为我指明了正确的方向,请在此处回答

于 2021-03-27T11:06:51.123 回答
0

就像我在评论中所说的那样,很可能会decode(type: Live.self, decoder: JSONDecoder())返回一个错误,因为您从 when 获取的 URLlink没有nil返回任何可以解码为Live.self.

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

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

let publisher2 = publisher1
   .flatMap {
       self.fetchLiveFeed($0.dates.first?.games.first?.link ?? "")
          .map { $0 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
          }
      })
于 2021-03-22T22:52:12.600 回答