问题描述
我的代码获取两个 JSON
变量并应在我的小部件上显示它们.小部件保持空白.如果没有小部件,它会显示我的应用程序中的所有内容.
My Code fetches two JSON
variables and should show them on my Widget.
The Widget stays blank. Without widget it shows me everything correct in my application.
我做错了什么?代码中的 API 仅用于测试,因此您也可以检查.我需要更改什么以使其显示在小部件中吗?
What am I doing wrong? The API in the code is only for testing so you can also check that. Is there something I need to change to make it show in the widget?
我的结构:
import Foundation
struct Results: Decodable {
let data: [Post]
}
struct Post: Decodable, Identifiable {
let id: String
var objectID: String {
return id
}
let home_name: String
let away_name: String
}
获取 JSON:
import Foundation
class NetworkManager: ObservableObject {
@Published var posts = [Post]()
@Published var test = ""
@Published var test2 = ""
func fetchData() {
if let url = URL(string: "https://livescore-api.com/api-client/teams/matches.json?number=10&team_id=19&key=I2zBIRH3S01Kf0At&secret=6kLvfRivnqeNKUzsW84F0LISMJC1KdvQ&number=7&team_id=46") {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (gettingInfo, response, error) in
if error == nil {
let decoder = JSONDecoder()
if let safeData = gettingInfo {
do {
let results = try decoder.decode(Results.self, from: safeData)
DispatchQueue.main.async {
self.posts = results.data
self.test = results.data[0].away_name
self.test2 = results.data[0].home_name
}
} catch {
print(error)
}
}
}
}
task.resume()
}
}
}
显示小部件:
import WidgetKit
import SwiftUI
import Intents
struct Provider: IntentTimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), configuration: ConfigurationIntent())
}
func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), configuration: configuration)
completion(entry)
}
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, configuration: configuration)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationIntent
}
struct WidgetNeuEntryView : View {
@ObservedObject var networkManager = NetworkManager()
var entry: Provider.Entry
var body: some View {
Text(networkManager.test)
}
}
@main
struct WidgetNeu: Widget {
let kind: String = "WidgetNeu"
var body: some WidgetConfiguration {
IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in
WidgetNeuEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
struct WidgetNeu_Previews: PreviewProvider {
static var previews: some View {
WidgetNeuEntryView(entry: SimpleEntry(date: Date(), configuration: ConfigurationIntent()))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
networkManager.test
应该显示为文本,但正如我所说,它是空白的.
networkManager.test
should be shown as text but as I said it is blank.
推荐答案
你不能像在你的应用程序中那样使用 ObservedObject
.
You can't use the ObservedObject
like you'd normally use in your App.
在小部件中,您使用 TimelineProvider
为您的视图创建 Entry
.
In Widgets you use a TimelineProvider
which creates an Entry
for your view.
- 为你的
TimelineEntry
添加另一个属性,我们称之为clubName
:
- Add another property to your
TimelineEntry
, let's call itclubName
:
struct SimpleEntry: TimelineEntry {
let date: Date
let clubName: String
}
- 更新
NetworkManager
并在completion
中返回结果:
- Update the
NetworkManager
and return results in thecompletion
:
class NetworkManager {
func fetchData(completion: @escaping ([Post]) -> Void) {
...
URLSession(configuration: .default).dataTask(with: url) { data, _, error in
...
let result = try JSONDecoder().decode(Results.self, from: data)
completion(result.data)
...
}
.resume()
}
}
- 使用
TimelineProvider
中的NetworkManager
并在fetchData
完成时创建时间线条目:
- Use the
NetworkManager
in theTimelineProvider
and create timelines entries when thefetchData
completes:
struct Provider: TimelineProvider {
var networkManager = NetworkManager()
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), clubName: "Club name")
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
let entry = SimpleEntry(date: Date(), clubName: "Club name")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
networkManager.fetchData { posts in
let entries = [
SimpleEntry(date: Date(), clubName: posts[0].home_name)
]
let timeline = Timeline(entries: entries, policy: .never)
completion(timeline)
}
}
}
- 在视图主体中使用
entry.clubName
:
struct WidgetNeuEntryView: View {
var entry: Provider.Entry
var body: some View {
VStack {
Text(entry.date, style: .time)
Text("Club: (entry.clubName)")
}
}
}
请注意,在上面的示例中,重新加载策略设置为 never
以仅加载数据一次.
如果您想自动重新加载时间线,您可以轻松地将其更改为 atEnd
或 after(date:)
.
You can easily change it to atEnd
or after(date:)
if you want to reload the timeline automatically.
如果您需要在任何时候手动重新加载时间线,您只需调用:
If you need to reload the timeline manually at any point you can just call:
WidgetCenter.shared.reloadAllTimelines()
这在 App 和 Widget 中都可以使用.
This will work in both App and Widget.
这是一个 GitHub 存储库,其中包含不同的小部件示例,包括网络小部件.
Here is a GitHub repository with different Widget examples including the Network Widget.
这篇关于如何刷新 Widget 数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!