2

I have written an app that has a class that will pull from a JSON online and parses it then return a string (the quote of the day).

I know it pulls the data correctly because it works the first time. In the widget library, it shows exactly what it is supposed to, as well as it does on the home screen.

The problem is when I restart the phone, it doesn't reload all the data into the widget.

The other problem is that it doesn't refresh the quote within 5 minutes of having turned to the next day. (I checked the API and I know they changed it. I also think I have it set to check every minute).

I have attached the code that browses the JSON for you here:

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]

Now here is the widget code. Sorry, I don't know exactly where the problem is so I have attached a lot of code to this question.

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))
    }
}

Thank you to anyone who takes the time to look at this.

pawello2222
  • 46,897
  • 22
  • 145
  • 209
ntm52
  • 33
  • 1
  • 5
  • This might help you: [How to refresh Widget data?](https://stackoverflow.com/questions/63976424/how-to-refresh-widget-data) – pawello2222 Sep 20 '20 at 18:26
  • Just note that refreshing a Widget every minute is probably a bad idea. There is likely a limit of available updates for your Widget (just as with the background fetch). – pawello2222 Sep 20 '20 at 18:30
  • Thank you so much @pawello2222 I don’t have my computer right now but your additions seem like they will be very effective and I’m very grateful – ntm52 Sep 21 '20 at 19:16
  • Does this answer your question? [How to refresh Widget data?](https://stackoverflow.com/questions/63976424/how-to-refresh-widget-data) – Andrew Dec 25 '20 at 08:40

1 Answers1

0

I have the same problem. the problem is, your Widget can not keep running, you can update your content when the main app is running OR it is in the background running. that means you can update your widget until 30 seconds after the main app goes in background mod. so what we can do is, wake our main app via Notification or BackgroundFetch to run widget for 30 seconds.