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

时间:2016-07-21 05:27:59

标签: ios swift swift2 nsurlsession nsoperationqueue

我想在下载后按顺序添加数组中的图像。我在逐个下载之后将图像附加到数组中,但它们不是按顺序排列的。任何人都可以告诉我这是最好的方法。

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
  全部完成

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都被完全下载。然后按已知顺序迭代。