Saving multiple images to Parse

300 Views Asked by At

So I have an array of images I've accessed from my xcassets for demonstration purposes. There are 150 images I'm trying to save to my parse server at one time using parse frameworks. Here is the code I have so far. The problem I have is my app cpu goes to 100% in the tests and drops to 0. Also the images aren't saving to parse. I was hoping someone could help me find an efficient way to save 150 images to parse.

var imageNameList: [String] {
    var imageNameList2:[String] = [] //[NSMutableArray]()
    for i in 0...149 {
        let imageName = String(format: "pic_%03d", Int(i))
        imageNameList2.append(imageName)
    }
    return imageNameList2
}
@IBAction func Continue(_ sender: Any) {
        for imageName in imageNameList {
            var objectForSave:PFObject = PFObject(className: "Clo")
            let object:UIImage = UIImage(named: imageName)!
            let tilesPF = imageNameList.map({ name in
                let data = UIImagePNGRepresentation(object as! UIImage)!
                let file = PFFile(data: data)

                let tile = PFObject(className: "Tile")
                tile["tile"] = file
            })

            objectForSave["tiles"] = tilesPF

            objectForSave.saveInBackground(block: { responseObject, error in

                //you'll want to save the object ID of the PFObject if you want to retrieve a specific image later
            })


        }

}
1

There are 1 best solutions below

2
danh On

The trouble is that the tight for-loop launches all of those requests concurrently causing some part of the http stack to bottleneck.

Instead, run the requests sequentially as follows (in my best approximation of Swift)...

func doOne(imageName: String, completion: (success: Bool)->()) {
    var objectForSave:PFObject = PFObject(className: "Clo")
    let object:UIImage = UIImage(named: imageName)!
    // ... OP code that forms the request
    objectForSave.saveInBackground(block: { responseObject, error in
        success(error == nil) 
    })
}

func doMany(imageNames: Array<String>, completion: (success: Bool)->()) {
    if (imageNames.count == 0) return completion(YES)
    let nextName = imageNames[0];

    self.doOne(imageName:imageNames[0] completion: {(success: Bool) -> Void in
        if (success) {
            let remainingNames = imageNames[1..imageNames.count-1]
            self.doMany(imageNames: remainingNames completion:completion)
        } else {
            completion(NO)
    })
}

In English, just in case I goofed the Swift, the idea is to factor out a single request into it's own function with a completion handler. Build a second function that takes an array of arguments to the network request, and use that array like a to-do list: do the first item on the list, when it completes, call itself recursively to do the remaining items.