在串行队列中串行下载图像非常慢

要求 我有一个要求,我收到一个JSON字典,我从中检索图像和内容文本的数组。 然后我必须在集合视图中显示具有相应内容的所有图像。

更新 –最重要的是我需要根据图像大小计算单元格大小,该图像大小按比例缩放到我想要的恒定宽度(可能不正确)我需要完全下载所有图像然后重新加载集合视图

问题 –但问题是,当我在后台线程中下载图像并填充在单独的数组中时。然后,由于我在并发队列中下载它们,因此无法以与JSON字典中相同的顺序添加图像。

我的解决方案 –所以我想通过将所有内容放在一个使我的检索数据非常慢的串行队列中来下载它们。 什么是有效的替代方案?

代码 –

let serialQueue = dispatch_queue_create("my serial queue", nil) dispatch_async(serialQueue, { print("This is first Method") for var i=0;i 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() }) } 

如果你使用并发队列,你肯定可以保留订单。 我认为你的代码几乎没有正确使用队列(为什么有sleep(2) ?)你的并发队列应该在forloop内部,这样它可以同时触发不同的块,并且他们将使用分配给它们的for循环的正确索引将结果图像放在正确的数组位置

 let sema = dispatch_semaphore_create(2); //depending how many downloads you want to go at once for i in 0.. 

一种更有效的方法是创建一个数据模型对象,它将代表您的图像链接和可选的UIImage。 像这样的东西:

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

现在,当您收到带有图像链接数组的JSON时,您可以创建数据模型数组,它将遵循以下顺序:

 let dataModel: [NetworkImage] 

因此,当您异步检索图像时,可以使用图像更新dataModel,因此不会影响订单。 这个想法可以根据您的需求进行改进。 您永远不应该对这类作业使用同步操作。

您可以使用调度组来使用此示例解决方案:

 //: 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)") } } 

安慰:

 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")]