按顺序将图像附加到数组中

Append images in array in sequence

我想在下载后按顺序将图片添加到数组中。一张一张下载后,我将图像附加到数组中,但它们没有按顺序排列。谁能告诉我最好的方法是什么。

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 download2
JPEG download1
JPEG download3
all done

尝试:

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)

这是一个非常快速和粗略的修复,当然还有更好的解决方案。问题的出现是因为操作队列中的操作是并发执行的,并且不能保证按它们开始的顺序完成。通过向循环中的先前操作添加依赖性,您可以确保它们按顺序执行

我不确定,但我认为,您无法控制下载顺序.. 意味着所有请求都通过管道传输到服务器(无论您创建 URL 对象的顺序如何)。您需要做的是,您必须维护包含 url 到实际数据映射的可变数组或字典,然后等待所有 url 完全下载。然后以已知顺序迭代。

您应该更改您的模型,这样图像的下载顺序就无关紧要了。例如,您有图像 URL 字符串数组:

var imageURLs: [String]

因此,您的 NSData 应该存储在由 URL 字符串键入的字典(或 NSCache)中:

var imageData = [String: NSData]()

然后当你下载数据时,你可以更新这个词典:

self.imageData[imageURL] = dtA

然后,当您以后需要检索此数据时,可以使用图像URL,例如:

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 直接调用 ,如上所示。