如何使SwiftUI小部件每分钟更新一次?

时间:2020-09-19 05:29:27

标签: swiftui widgetkit

我编写了一个应用程序,该应用程序的类将从在线JSON中提取并进行解析,然后返回一个字符串(当天的报价)。

我知道它可以正确提取数据,因为它是第一次工作。在小部件库中,它准确显示了它的预期功能,以及它在主屏幕上所做的一切。

问题是当我重启手机时,它没有将所有数据重新加载到小部件中。

另一个问题是,在转到第二天之后的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))
    }
}

感谢所有花时间查看此内容的人。

1 个答案:

答案 0 :(得分:1)

我也有同样的问题。问题是,您的 Widget 无法继续运行,您可以在主应用程序运行或在后台运行时更新您的内容。这意味着您可以在主应用程序进入后台模式后 30 秒内更新您的小部件。 所以我们可以做的是,通过 Notification 或 BackgroundFetch 唤醒我们的主应用程序以运行小部件 30 秒。

相关问题