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
}
})
SwiftUI
和 WidgetKit
的工作方式不同。我需要在 getTimeline
中为我的 IntentTimelineProvider
获取数据,然后为我的 TimelineEntry
添加一个 completion
处理程序。大量修改了我的 Combine
数据模型。所有功劳归于 @EmilioPelaez for pointing me in the right direction, .
我创建了一个 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
}
})
SwiftUI
和 WidgetKit
的工作方式不同。我需要在 getTimeline
中为我的 IntentTimelineProvider
获取数据,然后为我的 TimelineEntry
添加一个 completion
处理程序。大量修改了我的 Combine
数据模型。所有功劳归于 @EmilioPelaez for pointing me in the right direction,