2016-07-21 5 views
1

Я хочу добавить изображения в массив последовательно после загрузки. Я добавляю изображения в массив после загрузки один за другим, но они не находятся в последовательности. Может ли кто-нибудь рассказать мне, что это лучший способ сделать это.Добавление изображений в массив в последовательности

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

+0

Просьба пояснить, что вы подразумеваете под «в последовательности». – jsondwyer

+0

Вы можете выбрать GCD, он очень прост в использовании и имеет функции, такие как последовательная очередь, параллельная очередь. вот учебник для этого же - https://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1. –

+0

Я имею в виду, так как URL-адреса находятся в массиве. Например, 10 URL-адресов изображений находятся в массиве. Изображение нужно сохранить в том же номере индекса, что и его URL-адрес для сохранения по конкретному индексу. Но из-за асинхронных изображений загружаются в случайном порядке. Не в последовательности. Мне нужно сохранить все изображения в последовательности, потому что мне нужно использовать их со своими заголовками. Я загружаю эти изображения. 'http: //www.wcvb.com/9849860? format = rss_2.0 & view = feed' – ZAFAR007

ответ

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 напрямую, как показано выше.

+0

Спасибо, что Роб снова помог мне. Оно работает. Теперь я пытаюсь сортировать 'imageData = [String: NSData]()', потому что позже мне нужно использовать эти изображения с их названиями в 'tableViewCell' – ZAFAR007

+0

@ ZAFAR007 - Красота словаря заключается в том, что у вас нет сортировать. Вы можете использовать 'if let data = imageData [imageURLs [indexPath.row]], пусть image = UIImage (data: data) {...}'. – Rob

+0

Роб-ЖЖ. Я знаю о библиотеке «AlamofireImage», но из-за своих файлов библиотеки требуется больше памяти, поэтому я ее не использовал. Также я не хочу показывать изображения непосредственно в tableViewCell, потому что я сначала сохраняю эти изображения в «NSUserDefualts», а затем показываю в tableViewCell после извлечения изображений из NSUserDefaults. Потому что я хочу сделать мое приложение также для чтения в автономном режиме. Я также пытаюсь использовать 'dispatch_get_global_queue' с синхронной загрузкой, которая загружает изображения в последовательности, но из-за невозможности отмены папок я использую ваше решение' NSOperationQueue'. – ZAFAR007

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) 

это очень быстро и грубо исправить, там вполне может быть лучшим решением, конечно. Проблема возникает из-за того, что операции в очереди операций выполняются одновременно и не гарантируются для завершения, чтобы они запускались. Добавив зависимость от предыдущей операции в цикле, вы убедитесь, что они выполняются последовательно

+0

Может быть, это будет лучше, чем загрузить все в то же время и попытаться сортировать их снова – Tj3n

+0

я попробовать это, но тот же результат 'JPEG download0 JPEG download2 JPEG download1 JPEG download3 все сделано ' – ZAFAR007

+0

Это мой код, можете ли вы попытаться исправить это, когда вы дадите мне решение. Благодарю. 'https: //drive.google.com/open? id = 0B29ka7gbDAYxaXdsX05KTUFzYzA' – ZAFAR007

0

Я не уверен, но я думаю, вы не можете контролировать заказ на загрузку .. означает, что все запросы конвейерны на сервер (независимо от того, какой заказ вы создаете в объектах URL). Что вам нужно сделать, вы должны поддерживать изменяемый массив или словарь, который содержит URL-адрес для фактического сопоставления данных, а затем дождаться, пока все URL-адреса будут полностью загружены. Затем итерации в известном порядке.

+0

вы можете дать простой пример? – ZAFAR007

+0

Вам следует дождаться загрузки всего url (сохранить в том, что в одном изменяемом массиве, после его завершения, а затем отсортировать его) –

+1

или если вы хотите скачать по одному, то см. Ответ @ Andrey –

Смежные вопросы