如何使我的 SwiftUI 小部件每分钟更新一次?
How do I make my SwiftUI widget update every minute?
我写了一个应用程序,它有一个 class,它将从 JSON 在线提取并解析它,然后 return 一个字符串(当天的报价)。
我知道它可以正确地提取数据,因为它是第一次工作。在小部件库中,它准确显示了它应该显示的内容,以及它在主屏幕上的显示内容。
问题是当我重新启动 phone 时,它没有将所有数据重新加载到小部件中。
另一个问题是它不会在转到第二天后的 5 分钟内刷新报价。 (我检查了 API,我知道他们更改了它。我还认为我已将其设置为每分钟检查一次)。
我在这里附上了浏览JSON的代码:
public class QuoteManager: ObservableObject {
@Published var endQuote = String()
init() {
load()
}
func load() {
let url = URL(string: "https://zenquotes.io/api/today")!
URLSession.shared.dataTask(with: url) {(data,response,error) in
do {
if let d = data {
let quote = try JSONDecoder().decode([Contents].self, from: d)
let finalizedQuote = "\"\(quote[0].q)\" --\(quote[0].a)"
DispatchQueue.main.async {
self.endQuote = finalizedQuote
}
}else {
print("No Data")
}
} catch {
print ("Error")
}
}.resume()
}
func parseJSON(_ quoteData: Data) -> QuoteData? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(QuoteData.self, from: quoteData)
return decodedData
} catch {
return nil
}
}
}
struct Contents: Codable {
let q: String
let a: String
let h: String
}
typealias QuoteData = [Contents]
现在是小部件代码。抱歉,我不知道具体问题出在哪里,所以我附上了很多代码来解决这个问题。
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let date = Date()
let entry = SimpleEntry(date: date)
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let nextUpdateDate = Calendar.current.date(byAdding: .minute, value: 1, to: date)!
// Create the timeline with the entry and a reload policy with the date
// for the next update.
let timeline = Timeline(
entries:[entry],
policy: .after(nextUpdateDate)
)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
@ObservedObject var quoteManager = QuoteManager()
}
struct Quote_WidgetEntryView : View {
let quote: String
var body: some View {
Text(quote)
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.frame(maxHeight: .infinity)
.background(
Image("WidgetBackground")
.resizable()
)
}
}
@main
struct Quote_Widget: Widget {
let kind: String = "Quote_Widget"
@ObservedObject var quoteManager = QuoteManager()
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
Quote_WidgetEntryView(quote: quoteManager.endQuote)
}
.configurationDisplayName("Daily Quotes")
.description("A new quote everyday for inspiration and motivation!")
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
}
}
struct Quote_Widget_Previews: PreviewProvider {
static var previews: some View {
Quote_WidgetEntryView(quote: "Preview")
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}
感谢所有花时间看这篇文章的人。
我也遇到了同样的问题。问题是,您的 Widget 无法保持 运行ning,您可以在主应用 运行ning 或在后台 运行ning 时更新您的内容。这意味着您可以在主应用程序进入后台后 30 秒内更新小部件 mod。
所以我们可以做的是,通过 Notification 或 BackgroundFetch 将我们的主应用程序唤醒到 运行 小部件 30 秒。
我写了一个应用程序,它有一个 class,它将从 JSON 在线提取并解析它,然后 return 一个字符串(当天的报价)。
我知道它可以正确地提取数据,因为它是第一次工作。在小部件库中,它准确显示了它应该显示的内容,以及它在主屏幕上的显示内容。
问题是当我重新启动 phone 时,它没有将所有数据重新加载到小部件中。
另一个问题是它不会在转到第二天后的 5 分钟内刷新报价。 (我检查了 API,我知道他们更改了它。我还认为我已将其设置为每分钟检查一次)。
我在这里附上了浏览JSON的代码:
public class QuoteManager: ObservableObject {
@Published var endQuote = String()
init() {
load()
}
func load() {
let url = URL(string: "https://zenquotes.io/api/today")!
URLSession.shared.dataTask(with: url) {(data,response,error) in
do {
if let d = data {
let quote = try JSONDecoder().decode([Contents].self, from: d)
let finalizedQuote = "\"\(quote[0].q)\" --\(quote[0].a)"
DispatchQueue.main.async {
self.endQuote = finalizedQuote
}
}else {
print("No Data")
}
} catch {
print ("Error")
}
}.resume()
}
func parseJSON(_ quoteData: Data) -> QuoteData? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(QuoteData.self, from: quoteData)
return decodedData
} catch {
return nil
}
}
}
struct Contents: Codable {
let q: String
let a: String
let h: String
}
typealias QuoteData = [Contents]
现在是小部件代码。抱歉,我不知道具体问题出在哪里,所以我附上了很多代码来解决这个问题。
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let date = Date()
let entry = SimpleEntry(date: date)
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let nextUpdateDate = Calendar.current.date(byAdding: .minute, value: 1, to: date)!
// Create the timeline with the entry and a reload policy with the date
// for the next update.
let timeline = Timeline(
entries:[entry],
policy: .after(nextUpdateDate)
)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
@ObservedObject var quoteManager = QuoteManager()
}
struct Quote_WidgetEntryView : View {
let quote: String
var body: some View {
Text(quote)
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.frame(maxHeight: .infinity)
.background(
Image("WidgetBackground")
.resizable()
)
}
}
@main
struct Quote_Widget: Widget {
let kind: String = "Quote_Widget"
@ObservedObject var quoteManager = QuoteManager()
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
Quote_WidgetEntryView(quote: quoteManager.endQuote)
}
.configurationDisplayName("Daily Quotes")
.description("A new quote everyday for inspiration and motivation!")
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
}
}
struct Quote_Widget_Previews: PreviewProvider {
static var previews: some View {
Quote_WidgetEntryView(quote: "Preview")
.previewContext(WidgetPreviewContext(family: .systemMedium))
}
}
感谢所有花时间看这篇文章的人。
我也遇到了同样的问题。问题是,您的 Widget 无法保持 运行ning,您可以在主应用 运行ning 或在后台 运行ning 时更新您的内容。这意味着您可以在主应用程序进入后台后 30 秒内更新小部件 mod。 所以我们可以做的是,通过 Notification 或 BackgroundFetch 将我们的主应用程序唤醒到 运行 小部件 30 秒。