I have an existing Obj-C based app. One of its features is to show a UITableView of the last 10 entries from an RSS feed associated to the app.
I have created a Widget for this app to show whatever the most recent entry is on that RSS feed. I do this by parsing the RSS, adding that as the Timeline entry, and displaying it.
When you first install the app and add the widget, everything is good. It shows the last entry. However, if a new item is added to the RSS feed, it won't show up on the widget, no matter how long you wait. I can verify the item is there by installing fresh on a different device, and I'll see the new item, but the other device still shows the previous one. Here is how I am handling the timeline:
Here is the Swift file I am using to parse. If you notice, I am even including a call to reloadAllWidgets along with calling the completion handler.
I have created a Widget for this app to show whatever the most recent entry is on that RSS feed. I do this by parsing the RSS, adding that as the Timeline entry, and displaying it.
When you first install the app and add the widget, everything is good. It shows the last entry. However, if a new item is added to the RSS feed, it won't show up on the widget, no matter how long you wait. I can verify the item is there by installing fresh on a different device, and I'll see the new item, but the other device still shows the previous one. Here is how I am handling the timeline:
Code Block struct Provider: TimelineProvider { let textView = UILabel() @State private var rssItems:[RSSItem]? let feedParser = FeedParser() func placeholder(in context: Context) -> SimpleEntry { SimpleEntry(date: Date(), title:"News", description: "News article here", link: "Http://link", pubDate: "Today") } func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { let entry = SimpleEntry(date: Date(), title:"News", description: "News Article Here", link: "Http://link", pubDate: "Today") completion(entry) } func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> ()) { // WidgetCenter.shared.reloadAllTimelines() var entries: [SimpleEntry] = [] feedParser.parseFeed(url: "https://fritchcoc.wordpress.com/feed") {(rssItems) in self.rssItems = rssItems let currentDate = Date() let string1 = "Latest News: " let string2 = rssItems[0].title let dateString = rssItems[0].pubDate let dateFormatter = DateFormatter() dateFormatter.dateFormat = "EEE, d MMM yyyy HH:mm:ss zzz" dateFormatter.locale = Locale.init(identifier: "en_US") let dateObj = dateFormatter.date(from: dateString) dateFormatter.dateFormat = "MM-dd-yyyy" let newDateSTring = (dateFormatter.string(from: dateObj!)) let theURLTHING = URL(string: "game:///octo")! var appendString1 = string1+string2 let entry = SimpleEntry(date: currentDate, title:appendString1, description: rssItems[0].description, link: rssItems[0].link, pubDate: newDateSTring) entries.append(entry) let refreshDate = Calendar.current.date(byAdding: .minute, value: 2, to: Date())! let timeline = Timeline(entries: [entry], policy: .after(refreshDate)) completion(timeline) } } }
Here is the Swift file I am using to parse. If you notice, I am even including a call to reloadAllWidgets along with calling the completion handler.
Code Block import Foundation import WidgetKit struct RSSItem { var title: String var link: String = "" var description: String var pubDate: String } class FeedParser: NSObject, XMLParserDelegate { var rssItems: [RSSItem] = [] private var currentElement = "" private var currentTitle: String = "" { didSet { currentTitle = currentTitle.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } private var currentDescription: String = "" { didSet { currentDescription = currentDescription.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } private var currentPubDate: String = "" { didSet { currentPubDate = currentPubDate.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } private var currentLink: String = "" { didSet { currentLink = currentLink.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } } private var parserCompletionHandler: (([RSSItem]) -> Void)? func parseFeed(url: String, completionHandler: (([RSSItem]) -> Void)?) { // WidgetCenter.shared.reloadAllTimelines() self.parserCompletionHandler = completionHandler let request = URLRequest(url: URL(string: url)!) let urlSession = URLSession.shared let task = urlSession.dataTask(with: request) { (data, response, error) in guard let data = data else { if let error = error { print(error.localizedDescription) } return } /// parse our xml data let parser = XMLParser(data: data) parser.delegate = self parser.parse() } task.resume() } // MARK: - XML Parser Delegate func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { //WidgetCenter.shared.reloadAllTimelines() currentElement = elementName if currentElement == "item" { currentTitle = "" currentDescription = "" currentPubDate = "" currentLink = "" } } func parser(_ parser: XMLParser, foundCharacters string: String) { // WidgetCenter.shared.reloadAllTimelines() switch currentElement { case "title": currentTitle += string case "content:encoded" : currentDescription += string case "pubDate" : currentPubDate += string case "link" : currentLink += string default: break } } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { // WidgetCenter.shared.reloadAllTimelines() if elementName == "item" { let rssItem = RSSItem(title: currentTitle, link: currentLink, description: currentDescription, pubDate: currentPubDate) self.rssItems.append(rssItem) } } func parserDidEndDocument(_ parser: XMLParser) { WidgetCenter.shared.reloadAllTimelines() parserCompletionHandler?(rssItems) } func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { print(parseError.localizedDescription) } }