Downloading images serially in a serial queue very slow

点点圈 提交于 2019-12-12 20:06:08

问题


Requirement - I have a requirement in which I am receiving a JSON dictionary from which I am retrieving an array of images and content text. Then I have to display all the images with corresponding contents in a collection view.

Update - Above all I need to calculate the cell size based on image size scaled to the a constant width for which I fell that(may not be correct) I need all images to be downloaded completely then reload collection view

Problem - But the problem is that when I download the images in background thread and populate in separate arrays.Then the image cannot be added in the same order as they were in the JSON Dictionary since I am downloading them in a concurrent queue.

My Solution - So I thought of downloading them by putting everything in a serial queue which has made my retrieving data very slow. What can be an efficient alternative for this?

Code -

let serialQueue = dispatch_queue_create("my serial queue", nil)

            dispatch_async(serialQueue, {

                print("This is first Method")

                for var i=0;i<self.resultArr.count;i++//resultArr is my array of data's in the jsonDic
             {



                    sleep(2)

                    print(self.resultArr[i].valueForKey("profile_pic")! as! String)
                    if self.resultArr[i].valueForKey("profile_pic")! as! String != "Null" && self.resultArr[i].valueForKey("profile_pic")! as! String != "null" && self.resultArr[i].valueForKey("profile_pic")! as! String != "NULL" && self.resultArr[i].valueForKey("profile_pic")! as! String != ""
                    {
                        let imageUrl = UrlClass.imageUrlWithoutExtension + String(self.resultArr[i].valueForKey("profile_pic")!)
                        print(imageUrl)
                        let url = NSURL(string: imageUrl)
                        let imageData = NSData(contentsOfURL: url!)

                        self.contentlabelArr.insertObject(String(self.resultArr[i].valueForKey("content")!), atIndex: i)

                        if imageData != nil && imageData?.length > 0
                        {
                            print("this is \(i) image")
                            print(UIImage(data: imageData!))

                            self.imageArr.insertObject(UIImage(data: imageData!)!, atIndex: i)
                        }
                        else
                        {
                            print("\(i) image has nill")
                            self.imageArr.insertObject(UIImage(named: "logo.png")!, atIndex: i)
                        }

                    }
                    else
                    {
                        print("\(i) image has nill")
                        self.contentlabelArr.insertObject(String(self.resultArr[i].valueForKey("content")!), atIndex: i)
                        self.imageArr.insertObject(UIImage(named: "logo.png")!, atIndex: i)
                    }

                    print("\(i) times 5 is \(i * 5)")

                    if self.imageArr.count==self.resultArr.count
                    {
                         print(self.resultArr.count)
                         print(self.imageArr.count)
                        dispatch_async(dispatch_get_main_queue(),
                            {
                                print(self.resultArr.count)
                                print(self.imageArr.count)
                                print(self.imageArr)
                                print(self.contentlabelArr)
                                self.collectionView?.reloadData()
                        })
                    }

回答1:


you definitely can keep the order if you use a concurrent queue. i think your code as it stands pretty much doesnt use the queue correctly at all (and why is there a sleep(2)?) your concurrent queue should be inside the forloop so it can fire off the different blocks at the same time, and they will use the correct index of the for loop that was assigned to them to place the resulting image in the correct array location

let sema = dispatch_semaphore_create(2); //depending how many downloads you want to go at once
for i in 0..<self.resultArr.count {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {

        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

        //download images here, order of execution will not be guaranteed, but after they are finished, they will always put the images in the array at 'i' so it doesnt matter

        dispatch_semaphore_signal(sema);
    })
}



回答2:


A more efficient way would be to create a data model object which will represent you image link and the optional UIImage. Something like this:

class NetworkImage {
    let imageURL: String!
    let image: UIImage?
}

Now when you receive your JSON with image links array, you can create your data model array, which will respect the order:

let dataModel: [NetworkImage]

So when you will retrieve your images asynchronously, you can update your dataModel with your image, so no order will be affected. The idea can be evolved suiting your needs. You should never use sync operations for this kind of jobs.




回答3:


You may play around with this sample solution, utilising dispatch groups:

//: Playground - noun: a place where people can play

import UIKit
import Dispatch
import XCPlayground
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true


class Record {
    init(text: String, imageURL: String) {
        self.text = text
        self.imageURL = imageURL
        self.image = nil
    }
    var text: String
    var imageURL: String
    var image: String?
}

extension Record: CustomStringConvertible {
    var description: String {
        return "text: \(text), imageURL: \(imageURL), image: \(image)"
    }
}

// Fetch text and image url, but no image.
func fetchRecords(completion: ([Record]?, ErrorType?) -> ()) {
    let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
    dispatch_after(delayInNanoSeconds, dispatch_get_global_queue(0, 0)) {
        let result: [Record] = [
            Record(text: "Aaa", imageURL: "path/image1"),
            Record(text: "Bbb", imageURL: "path/image2"),
            Record(text: "Ccc", imageURL: "path/image3")
        ]
        completion(result, nil)
    }
}

// fetch an image
func fetchImage(url: String, completion: (String?, ErrorType?) -> () ) {
    let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
    dispatch_after(delayInNanoSeconds, dispatch_get_global_queue(0, 0)) {
        let image = url
        completion(image, nil)
    }
}

// Put everything together: 
// 1) Fetch an array of records, omitting the image
// 2) When this is finished, in parallel, for each record 
//    fetch each image.
// 3) When all is finished, call the completion handler containing
//    the records including the images
func fetchRecordsWithImages(completion: ([Record]?, ErrorType?) -> () ) {
    fetchRecords { (result, error) in
        if let records = result {
            let grp = dispatch_group_create()
            records.forEach { record in
                dispatch_group_enter(grp)
                fetchImage(record.imageURL) { (image, error) in
                    if let image = image {
                        record.image = image
                    }
                    dispatch_group_leave(grp)
                }
            }
            dispatch_group_notify(grp, dispatch_get_global_queue(0, 0)) {
                completion(records, nil)
            }
        }
    }
}



fetchRecordsWithImages() { (records, error) in
    if let records = records {
        print("Records: \(records)")
    }
}

Console:

Records: [text: Aaa, imageURL: path/image1, image: Optional("path/image1"), text: Bbb, imageURL: path/image2, image: Optional("path/image2"), text: Ccc, imageURL: path/image3, image: Optional("path/image3")]


来源:https://stackoverflow.com/questions/36908183/downloading-images-serially-in-a-serial-queue-very-slow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!