• Почему сменяются ячейки в UICollectionView?

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

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

    Например, мы увидели ячейку №1, сработал метод загрузки изображения, пошел запрос на адрес, в этом время ячейка ушла из области, и мы увидели другую, она тоже посылает запрос на сервер, но в этом время у нас приходит ответ с первого запроса, и ячейка №2 уже получит по своему запросу, но данные будут от первого запроса, и соответственно подставится неправильное изображение.

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

    Я предлагаю следующее решение:
    Ставим наблюдателя, при получении строки с адресом изображения будет проверять, можно ли сформировать ссылку из указанного адреса, если не получится - тогда поставит дефолтное изображение

    var imageURLString:   String? {
            
            didSet {
                
                DispatchQueue.global(qos: .utility).async { [unowned self] in
                    
                    guard imageURLString    != "",
                          let imageURLString = self.imageURLString,
                          let imageURL       = URL(string: imageURLString) else {
                              
                              DispatchQueue.main.async {
                                  
                                  self.ImageView.image = UIImage(named: "default")
                                  
                              }
                              
                              return
                              
                          }
                    
                    loadImage(imageURL: imageURL)
                    
                }
                
                
            }
            
        }


    Если ссылка получена, вызывается этот метод, который получит данные и подставит в изображение, либо поставит дефолтную картинку, если данные не пришли по тем или иным причинам

    fileprivate func loadImage(imageURL: URL)  {
            
            dataTask = URLSession.shared.dataTask(with: imageURL, completionHandler: { data, response, error in
                
                if let data = data,
                   let image = UIImage(data: data) {
                    
                    DispatchQueue.main.async { [unowned self] in
                        
                        self.ImageView.image = image
                        
                    }
                    
                } else {
                    
                    DispatchQueue.main.async { [unowned self] in
                        
                        self.ImageView.image = UIImage(named: "default")
                        
                    }
                    
                }
                
            })
            
            dataTask?.resume()
            
        }


    Самое главное. Метод остановит загрузку если ячейка была удалена из области видимости.

    override func prepareForReuse()            {
            super.prepareForReuse()
            
            dataTask?.cancel()
            
            ImageView.image = UIImage(named: "default")
        }


    Код выше - прописан в классе ячейки коллекции.
    Ответ написан
    1 комментарий
  • Почему сменяются ячейки в UICollectionView?

    briahas
    @briahas
    ObjC, Swift, Python
    Переосмыслите свой подход к заполнению ячеек контентом. Т.е. либо
    - на момент заполнения контент уже должен быть, и достаточно его просто разместить в ячейке;
    либо
    - (если первый вариант невозможен) заполнять ячейку "пустым" контентом, а параллельно грузить контент асинхронно, но прерывать загрузку контента если ячейка ушла из видимого диапазона.
    Ответ написан
    2 комментария