0

I'm downloading five XML files from the web server using Alamofire and parsing them using SWXMLHash. The last file depends on the first four files in a way that some of its entries refer to the entries contain in the first four. I use cascading style structure for download code to ensure all four files are downloaded before downloading of the last file can start.

    let destination: DownloadRequest.DownloadFileDestination = { _, _ in
        let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,
                                                                .userDomainMask, true)[0]
        let documentsURL = URL(fileURLWithPath: documentsPath, isDirectory: true)
        let fileURL = documentsURL.appendingPathComponent("image.png")

        return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
    }



    // Download Category files
    Alamofire.download(self.ottawaOpenDataCategoriesURL, to:
        destination)
        .downloadProgress { progress in
            //print("Download Progress for Category: \(progress.fractionCompleted)")
            if let pv = self.progressViewController {
               pv.updateProgress(progress.fractionCompleted * 100.0) //Alamofire returns 1 for complete process
            }
        }

        .responseData { response in
            // Check 304 response to see if new file is available
            if response.response?.statusCode == self.HTTP_STATUS_FILE_NOT_CHANGE {
                return
            }

            if let data = response.result.value {
                let xml = self.initXMLParser(data: data)
                self.storeCategoryXMLStream(xml)
            }


            // After complete downloading or get error, try download Options
            Alamofire.download(self.ottawaOpenDataOptionsURL, to:
                destination)
                .downloadProgress { progress in
                    if let pv = self.progressViewController {
                        pv.updateProgress(progress.fractionCompleted * 100.0) //Alamofire returns 1 for complete process
                    }
                }

                .responseData { response in
                    // Check 304 response to see if new file is available
                    if response.response?.statusCode == self.HTTP_STATUS_FILE_NOT_CHANGE {
                        return
                    }

                    if let data = response.result.value {
                        let xml = self.initXMLParser(data: data)
                        self.storeEventOptionsXMLStream(xml)
                    }

                    // After complete downloading or get error, try download Locations
                    Alamofire.download(self.ottawaOpenDataLocationsURL,  to:
                        destination)
                        .downloadProgress { progress in
                            if let pv = self.progressViewController {
                                pv.updateProgress(progress.fractionCompleted * 100.0) //Alamofire returns 1 for complete process
                            }
                        }

                        .responseData { response in
                            // Check 304 response to see if new file is available
                            if response.response?.statusCode == self.HTTP_STATUS_FILE_NOT_CHANGE {
                                return
                            }

                            if let data = response.result.value {
                                let xml = self.initXMLParser(data: data)
                                self.storeVenuesXMLStream(xml)
                            }

                            // After complete downloading or get error, try download CitrSectors
                            Alamofire.download(self.ottawaOpenDataCitySectorsURL,  to:
                                destination)
                                .downloadProgress { progress in
                                    if let pv = self.progressViewController {
                                        pv.updateProgress(progress.fractionCompleted * 100.0) //Alamofire returns 1 for complete process
                                    }
                                }

                                .responseData { response in
                                    // Check 304 response to see if new file is available
                                    if response.response?.statusCode == self.HTTP_STATUS_FILE_NOT_CHANGE {
                                        return
                                    }

                                    if let data = response.result.value {
                                        let xml = self.initXMLParser(data: data)
                                        self.storeCitySectorsXMLStream(xml)
                                    }


                                    // After complete downloading or get error, try download events
                                    Alamofire.download(self.ottawaOpenDataEventsURL, to:
                                        destination)
                                        .downloadProgress { progress in
                                            if let pv = self.progressViewController {
                                                pv.updateProgress(progress.fractionCompleted * 100.0) //Alamofire returns 1 for complete process
                                            }
                                        }

                                        .responseData { response in
                                            // Check 304 response to see if new file is available
                                            if response.response?.statusCode == self.HTTP_STATUS_FILE_NOT_CHANGE {
                                                return
                                            }

                                            if let data = response.result.value {
                                                let xml = self.initXMLParser(data: data)
                                                self.storeEventsXMLStream(xml)
                                            }

                                        }
                                }
                        }
                }

        }

As you can see, each download segment waits for the previous one to complete. Also, the progress bar is updated during download process. Most XML files are from small to decent size (80 Lines - 10K lines) and the last one is the largest and contains about 200K lines.

I'm not sure if it's because of cascading style structure, but it takes about 10 seconds to download and parse the first four files. Is it possible to make it faster? I just want to know if I can improve efficiency. Here's a screenshot of cpu usage and mem usage.

enter image description here

P.S I'm running this app on simulator.

KMC
  • 1,677
  • 3
  • 26
  • 55

1 Answers1

1

Since the first 4 downloads aren't interdependent, you could download them simultaneously, and only when all 4 of those are received start the 5th download. Use a dispatch group to synchronize the execution of the 5th download.

In short, the whole operation looks like:

let group = DispatchGroup()

group.enter()
Alamofire.download(first url).responseData {
    process first url
    group.leave()
}

group.enter()
Alamofire.download(second url).responseData {
    process second url
    group.leave()
}

repeat for third and fourth url

group.notify(queue:Dispatch.main) {
    Alamofire.download(fifth url).responseData {
        process 5th url
    }
}
David Berry
  • 40,941
  • 12
  • 84
  • 95
  • Thanks! It improves quite significantly(down to about 4 seconds). But I had to fix group.notify usage to "group.notify(queue: .main)". Could you fix that for reference sake? I'll mark it as correct one after. Thanks again. – KMC Mar 21 '17 at 10:49
  • One other thing to add regarding parsing larger files - SWXMLHash can do lazy parsing so, depending on if you're reading everything from the file or just specific parts, lazy loading can dramatically increase performance. See https://github.com/drmohundro/SWXMLHash#configuration. – David Mohundro Mar 21 '17 at 13:55