2017-02-22 27 views
0

Во время недавнего интервью мне задали такой сценарий, как #9 этих общих вопросов для интервью, связанных с загрузкой изображений асинхронно в ячейку представления таблицы. Я понимаю необходимость его вызова в cellForIndexPath и асинхронно, но я был в тупике относительно того, как проверить, будет ли ячейка все еще видна после завершения асинхронного вызова (см. Выдержку № 3 пули ниже). Другими словами, после асинхронного вызова, как я могу определить, была ли ячейка таблицы, которую я получала данные, все еще находится в представлении.Асинхронная выборка завершена: отображается ли ячейка?

Когда изображение загрузило на ячейку, мы должны проверить, что клетка еще в представлении или она была повторно использована в другой части данных. Если он был повторно использован, мы должны отбросить изображение, , иначе нам нужно переключиться обратно в основной поток, чтобы изменить изображение на ячейку.

+0

Вы можете назначить тег ячейке, а затем проверить, присутствует ли ячейка с этим тегом в таблицеView или нет. Вы можете легко видеть видимые ячейки, поскольку UITableView предоставляет метод для этого. –

+0

Используйте отличную асинхронную библиотеку, такую ​​как AlamofireImage/Kingfisher и т. Д., Которая позаботится о загрузке вашего асинхронного изображения. С другой стороны, прикрепите тег для своей ячейки, или вы можете проверить на indexpath.row, чтобы получить видимую ячейку и реализовать свою логику изображения. – Tuhin

ответ

1

Вы должны начать загрузку изображения в фоновом режиме с помощью механизма обратного вызова, который может решить, должно ли изображение отображаться после его загрузки.

Один из вариантов был бы подклассом UIImageView или UITableViewCell и сохранил ссылку на изображение NSURL. Затем, когда вы вызываете обратный вызов, вы можете проверить, является ли изображение или кеш-адрес ячейки одним из изображений, которые у вас есть, и решили отобразить его или нет.

Я бы не рекомендовал на:

  • опирающегося на маркере зрения, поскольку это требует какой-то ассоциации таблицы между NSURL и целым числом, которое требует объект менеджера и не помогает повторное использование кода
  • опираясь на indexPath клетки в виде обновлений таблицы или ячеек повторного использования для других путей индекса может произойти в то время как запрос сети произошел

более продвинутых вариантов описан в Associated Objects, by NSHipster:

При расширении поведения встроенного класса может потребоваться отслеживание дополнительного состояния. Это пример использования учебника для связанных объектов. Например, AFNetworking использует связанные объекты в своей категории UIImageView для хранения объекта операции запроса, используемого для асинхронного извлечения удаленного изображения по определенному URL-адресу.

+0

Спасибо за ответ @DirtyHarry. Ваше решение аналогично тому, что я имел в виду, когда мозговой штурм решений для этого вопроса. Вы можете взглянуть на мой [пример кода] (http://pastebin.com/EtwWxGN4) на Pastebin, пожалуйста? Я не думаю, что код внутри обратного вызова правильный. Какое необходимое изменение нужно сделать, чтобы получить видимую ячейку, сравнить кешированный URL-адрес ячейки с URL-адресом изображения? – galenom

+0

Я думаю, что ваш код в порядке. Возможно, просто вызовите cell.setNeedsLayout(), чтобы заставить ячейку рисовать изображение с правильным аспектом. Я создал здесь демо-код, который отлично работает: https://github.com/Bootstragram/Martinet/blob/master/Example/Martinet/DemoAsyncDownloadsPresenter.swift –

+0

Отмечено как правильно. Другое решение с использованием метода экземпляра tableviews [cellForRow (at:)] (https://developer.apple.com/reference/uikit/uitableview/1614983-cellforrow). Внутри асинхронного блока я получаю ячейку с активным indexPath. Если возвращает nil, ячейка для этого указательного пути не отображается, поэтому я не устанавливаю изображение. 'DispatchQueue.main.async { если пусть newCell = self.tableView.cellForRow (at: indexPath) как? ContactCell { newCell.imageView? .image = image newCell.layoutSubviews() } } ' – galenom

1

Вы можете просто проверить, является ли UITableViewCell еще в представлении или нет, используя следующий метод: UITableView

// возвращение indexPaths, которые видны

var indexPathsForVisibleRows: [IndexPath]? 

Не проверить ли для перезагрузки определенной строки или нет, вы можете сделать это с помощью следующего метода:

func downloadImageForCell(indexPath: IndexPath) { 

    // Asynchronous download method here 

    // After download is completed. Call the below in mainqueue 
    if let indexPaths:[IndexPath] = self.tableView.indexPathsForVisibleRows { 
     // the above line checks if indexPath is available 
     if indexPaths.contains(indexPath) { 
      self.tableView.reloadRows(at: [indexPath], with: UITableViewRowAnimation.none) 
     } 
    } 
} 

Пожалуйста, дайте мне знать, если у вас возникли проблемы с внедрением этого кода.

+0

Предупреждение: если таблица обновляется во время сетевого запроса, индексная ячейка ячейки могла бы быть изменена. Таким образом, могут возникать параллельные вызовы для одного и того же indexPath, и если первый запрос занимает больше 2-го, вы получите неправильное изображение. –

+0

@ DirtyHenry, в текущем сценарии четко указано, что он загружает изображения для 'UITableViewCell'. Это означает, что текущий сетевой вызов предназначен для обновления изображений в уже извлеченных данных. Итак, я считаю, что это безопасная ставка для текущего сценария – KrishnaCA

+0

После более пристального взгляда, я все еще не думаю, что это так. Что делать, если пользователь прокручивает представление таблицы, а ячейка повторно используется для другого indexPath? Тогда 'self.tableView.indexPath (cell: cell)' может возвращать indexPath, в котором вы не хотите, чтобы ваше изображение попало. –