Too many files open

Hi, i have a problem, while download photos from my server get this error.

Error dnssd_clientstub deliver_request: socketpair failed 24 (Too many open files)

__NSCFLocalDownloadFile: error 24 opening for ioChannel, file: /private/var/mobile/Containers/Data/Application/6C28AF76-1BFA-4324-935A-E3655D273986/tmp/CFNetworkDownload_6VkNHA.tmp

There are 5000 photos and only download 300. I think alamofire download all photos simultaneus and the iphone memory crash.

This is my source code and my platform is, xcode 8, swift 3.0.1 and iphone 6 64gb with the latest iOS,

Thanks.

func SyncFotos() {

    let parametro: Parameters = [
        "empresa": "lita8x",

        "inventario": "1"

    ]



    self.lblSync2.text = "Sincronizando Fotos"
  
    Alamofire.request("http://litani2.dyndns.org:8080/litani-web/webservice/articulosa.php", parameters: parametro, encoding: URLEncoding.default)
        .responseJSON { response in
            if let result = response.result.value {
                if((result) != nil) {
                    let swiftyJsonVar = JSON(result)
                    if let resData = swiftyJsonVar["productos"].arrayObject {
                        let arrRes = resData as! [[String:AnyObject]]
                        let xcuenta = arrRes.count
                        var xconteo = 0
                        DispatchQueue.global(qos: .background).async {
                          
                            for articulo in arrRes {
                                let xcodigo = articulo["codigo"] as! String
                                let nombre = xcodigo+".jpg"
                                // Eliminamos la foto primero
                                let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
                                let filePath = documentsURL.appendingPathComponent(nombre).path
                              
                                if FileManager.default.fileExists(atPath: filePath) {

                                } else {

                                    let url = "http://litani2.dyndns.org:8080/litani-web/imagenes/"+nombre

                                    let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)

                                    Alamofire.download(url, to: destination).response { response in
                                        print("DEBUG: Request \(nombre)")
                                    }
                                    print(url)                                      
                                }
                                xconteo=xconteo+1
                                DispatchQueue.main.async {
                                    self.lblSync2.text = "Sincronizando Fotos \(xconteo) de \(xcuenta)"
                                    if (xconteo == xcuenta) {
                                        self.lblSync2.text = "Fotos Sincronizadas"

                                    }

                                }
                            }
                          
                        } // Dispatch

                    } // if let resData
                } // if((result) != nil)
            } // if let result
            self.lblSync2.text = "Sincronizar Fotos Culminado"

    } 
}

The way I would approach this is to place all of your URLs in an array or similar to represent all the images you want to fetch. You could create another structure - probably a dictionary or set because you want fast lookup - which is initially empty. The second structure has a custom setter.

You begin the process by removing the first element from the URL array and moving it to the pending structure, then initiating the network request. This structure represents the number of open or pending fetches.

Whenever something is added (i.e. the first operation) or removed (a request completes, so you remove the URL from the pending structure) the setter has the opportunity to check the structure to see how many network operations are currently pending. If there are less than your maximum you can start another one. If there are greater than or equal to the maximum then you do not start another one.

To make this work it will be important to ensure you do not have race conditions (fix the state of the data structures before commencing network tasks) and be sure to handle all network termination conditions - for example if the request ends with an error then you must also remove that URL from the pending structure.

If you work through the process you will see that from the initial single request, requests will be made until the maximum number of pending requests is active and as each terminates a new request will be made. This continues until all the requests have been handled and finally as requests complete and there are no remaining URLs to request in the first array, the number of requests in the pending array will drop to zero.

Finally - nothing wrong with AlamoFire but URLSession is now very, very good - it’s worth a look and maybe going vanilla. Also you have some fairly deep indentation there - you could use guard to avoid the pyramid of doom.

Very Thanks for your answer.

Do you make a example?