I'm building a RSS parser in Swift for MacOS. It won't use any windows, everything will be shown in the Menu Bar.
I have a problem where I'm parsing multiple URL:s using Alamofire and AlamofireRSSParser and I would like to add the result into a list and thereafter sort the articles from the feed according to the date it was published.
For now it works and everything loads into the sub menu (NSMenu) and into the NSStatusBar but when I try load all the articles from the feeds then list returns empty.
I'm guessing this occurs because of Alamofire runs async. If that's the problem do I have to write my own parser or can I run a separate thread handling Alamofires url request and AlamofireRSSparser parsing?
I've tried to execute the URL request and RSS/XML parsing using DispatchQueue to make the call to loadRSS wait until the list has been filled but alas no luck.
This is how the code looks for now. The program loads all the feeds from a local xml file where I have separated the different using a tag called category. The categories can be seen in the picture "Sport", "Ekonomi" and so on. Each category can hold a different amount of URL:s. Each URL are sent to the AlamofireRSS parser and the result is returned back into the NSMenu that I sent in as a parameter (the line "let sub = loadRss(outline: outline, subMenu: sub"). The NSMenu is then added as a submenu for each category, so the category named "Sport" will only show sport articles.
If I try to print the NSMenu "sub" then it's always empty and also if I change the output from loadRSS to a list instead of NSMenu, the list is always empty even though the list is filled in loadRSS (if I use list.append where I now use subMenu.addItem()).
What should I do to be able to sync the parsing of the URL:s with the return of a list so I can sort the resulting articles, and also how is it possible for the NSMenu to print empty and still be able to display the articles in the Menu Bar?
Sorry if the code is bad, it's my first Swift project.
///Used to read the RSS. Is called when the user presses the "Refresh item"
@objc func refresh() {
createMenu()
for i in 0...categories.endIndex-1 {
var sub = NSMenu()
var categoryItem = NSMenuItem()
categoryItem.title = categories[i].title
for outline in categories[i].outlines {
let sub = loadRss(outline: outline, subMenu: sub)
print(sub.items)
}
categoryItem.submenu = sub
categoryItem.target = self
statusBarMenu.addItem(categoryItem)
statusItem?.menu = statusBarMenu
}
statusBarMenu.addItem(quitItem)
statusBarMenu.addItem(refreshItem)
}
func laodRss(outline: Outline, subMenu: NSMenu) -> NSMenu {
var articleList = [NSMenuItem]()
let url = URL(string: outline.xmlUrl)!
AF.request(url).responseRSS() { (response) -> Void in
if let feed: RSSFeed = response.value {
for item in feed.items {
let article = NSMenuItem()
let timeString = self.formatDate(item: item)
if timeString != "" {
var title = self.shortenText(item: item.title!)
title = title + " " + timeString
let someObj: NSString = item.link! as NSString
article.representedObject = someObj
article.action = #selector(self.openBrowser(urlSender:))
article.title = title
//// Get the url from the article and add /favicon.ico to get the image
//// Will add the image to each article to indicate the source
let url = URL(string: outline.icon)
self.getData(from: url!) { data, response, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async() { [weak self] in
article.image = NSImage(data: data)
article.image?.size = CGSize(width: 15, height: 15)
}
}
subMenu.addItem(article)
}
}
}
}
return subMenu
}