kerbelda
kerbelda

Reputation: 345

Async call within Async call not executed

I'm trying to retrieve the XML from an rss feed, get the links for each article, and then extract info from those articles. I'm using AEXML to get the xml, and ReadabilityKit for link extraction.

I'm successfully pulling the links from the XML, but the parser call on Readability is never executing. I don't want this on the main thread as it blocks all UI, but so far that's the only way I've made it work. Code is below (removed that dispatch get main queue):

func retrieveXML() {
    let request = NSURLRequest(URL: NSURL(string: "<XML URL HERE>")!)
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        (data, response, error) in

        if data == nil {
            print("\n\ndataTaskWithRequest error: \(error)")
            return
        }

        do {
            let xmlDoc = try AEXMLDocument(xmlData: data!)
            for child in xmlDoc.root.children {

                if let postURL = child["id"].value {

                    let url = NSURL(string: postURL)
                    let parser = Readability(url: url!)
                    let title = parser.title()
                    print("TITLE: \(title)")
                }
            }
        } catch {
            print(error)
        }
    }
    task.resume()
}

Upvotes: 0

Views: 68

Answers (2)

Rob
Rob

Reputation: 438467

The problem is that Readability is deadlocking. You're calling it from a NSURLSession completion block (which defaults to a serial queue), but Readability blocks that queue with a semaphore until its own network request is completed. So Readability is deadlocking because it's blocking a thread waiting for a semaphore signal that is supposed to be sent from the same thread it is blocking.

You can fix this by asynchronously dispatching the code that instantiates Readability to a separate queue (e.g. a global queue).

dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)) {
    let url = NSURL(string: postURL)
    let parser = Readability(url: url!)
    let title = parser.title()
    print("TITLE: \(title)")
}

It looks like that API has been updated to run asynchronously, so get the latest version and this deadlocking issue is eliminated and the above asynchronous dispatch will not be needed. You'll obviously have to employ the completion handler pattern of the updated API.

Upvotes: 0

zapletnev
zapletnev

Reputation: 503

Thanks for reporting. The new version is available in cocoa pods and cartage with a new aync API. Sync API is removed from the project.

Readability.parse(url: articleUrl, { data in
  let title = data?.title
  let description = data?.description
  let keywords = data?.keywords
  let imageUrl = data?.topImage
  let videoUrl = data?.topVideo
})

Thanks for your contribution! For more info please check README https://github.com/exyte/ReadabilityKit

Upvotes: 1

Related Questions