我想在下载后按顺序添加数组中的图像。我在逐个下载之后将图像附加到数组中,但它们不是按顺序排列的。任何人都可以告诉我这是最好的方法。
var queue: NSOperationQueue = {
let _queue = NSOperationQueue()
_queue.maxConcurrentOperationCount = 4
return _queue
}()
var imageArrayNsData : [NSData] = []
let session = NSURLSession.sharedSession()
@IBAction func didClickOnStart(sender: AnyObject) {
queue.cancelAllOperations()
let completionOperation = NSBlockOperation() {
print("all done")
}
for (index, imageURL) in imageURLs.enumerate() {
let operation = ImageNetworkOperation(session: session, urlString: imageURL) { image, response, error in
let dtA : NSData = NSData(data: UIImageJPEGRepresentation(image!, 0.75)!)
self.imageArrayNsData.append(dtA)
print("JPEG download\(index)")
}
completionOperation.addDependency(operation)
queue.addOperation(operation)
}
NSOperationQueue.mainQueue().addOperation(completionOperation)
}
结果输出:
JPEG download0
JPEG下载2
JPEG下载1
JPEG下载3
全部完成
答案 0 :(得分:4)
您应该更改模型,以便下载图像的顺序无关紧要。例如,您拥有图像URL字符串数组:
var imageURLs: [String]
因此,您的NSData
应存储在由该网址字符串键入的字典(或NSCache
)中:
var imageData = [String: NSData]()
然后,当您下载数据时,您可以更新此词典:
self.imageData[imageURL] = dtA
然后,当您需要稍后检索此数据时,您可以使用imageURL,例如:
let data = imageData[imageURLs[index]]
或者您可以将其定义为[Int: NSData]
并使用数字索引作为关键字。但是这个想法是你可以使用字典,然后你收到响应的顺序无关紧要,但你仍然享受做并发请求的性能优势。
我建议的是:
var imageData = [String: NSData]()
@IBAction func didClickOnStart(sender: AnyObject) {
queue.cancelAllOperations()
let completionOperation = NSBlockOperation() {
print("all done")
}
for (index, imageURL) in imageURLs.enumerate() {
let operation = DataOperation(session: session, urlString: imageURL) { data, response, error in
guard let data = data where error == nil else { return }
guard let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode == 200 else { return }
NSOperationQueue.mainQueue().addOperationWithBlock {
self.imageData[imageURL] = data
}
print("JPEG download\(index)")
}
completionOperation.addDependency(operation)
queue.addOperation(operation)
}
NSOperationQueue.mainQueue().addOperation(completionOperation)
}
然后像这样访问它:
if let data = imageData[imageURLs[index]], let image = UIImage(data: data) {
// use `image` here
}
或者
var imageData = [Int: NSData]()
@IBAction func didClickOnStart(sender: AnyObject) {
queue.cancelAllOperations()
let completionOperation = NSBlockOperation() {
print("all done")
}
for (index, imageURL) in imageURLs.enumerate() {
let operation = DataOperation(session: session, urlString: imageURL) { data, response, error in
guard let data = data where error == nil else { return }
guard let httpResponse = response as? NSHTTPURLResponse where httpResponse.statusCode == 200 else { return }
NSOperationQueue.mainQueue().addOperationWithBlock {
self.imageData[index] = data
}
print("JPEG download\(index)")
}
completionOperation.addDependency(operation)
queue.addOperation(operation)
}
NSOperationQueue.mainQueue().addOperation(completionOperation)
}
并按如下方式访问:
if let data = imageData[index], let image = UIImage(data: data) {
// use `image` here
}
注意,ImageNetworkOperation
只是调用DataOperation
来获取NSData
,然后将其转换为UIImage
。如果您真的想要原始NSData
,我建议绕过ImageNetworkOperation
并直接致电DataOperation
,如上所示。
答案 1 :(得分:0)
尝试:
var previousOperation : NSOperation! = nil
for (index, imageURL) in imageURLs.enumerate()
{
let operation = ImageNetworkOperation(session: session, urlString: imageURL)
{ image, response, error in
let dtA : NSData = NSData(data: UIImageJPEGRepresentation(image!, 0.75)!)
self.imageArrayNsData.append(dtA)
print("JPEG download\(index)")
}
completionOperation.addDependency(operation)
if (previousOperation != nil)
{
operation.addDependency(previousOperation)
}
previousOperation = operation
queue.addOperation(operation)
}
NSOperationQueue.mainQueue().addOperation(completionOperation)
这是一个非常快速和粗略的解决方案,当然可能是一个更好的解决方案。出现此问题是因为操作队列中的操作是同时执行的,并且无法保证在它们启动时完成。通过向循环中的先前操作添加依赖性,您可以确保它们按顺序执行
答案 2 :(得分:0)
我不确定,但我认为,您无法控制下载顺序..意味着所有请求都被流水线化到服务器(无论您创建URL对象的顺序如何)。你需要做的是,你必须维护包含url到实际数据映射的可变数组或字典,然后等到所有url都被完全下载。然后按已知顺序迭代。