@RememberMeOne

Как решить проблему с потоками при обработке данных?

Здравствуйте, коллеги.
Столкнулся с проблемой с отображением данных.
Есть VC в нем реализован CollectionVC.

Надо вывести в CollectionVC несколько картинок, подкачанных через URL.

Сама проблема: функция dataProcessing() перебирает данные и вытаскивает строку с которой в последствии происходит загрузка картинки. С помощью функции я заполняю массив, но как понимаю, данные не успевают дойти до адрессата до загрузки интерфейса и в CollectionVC ничего не выводится.
print(imageArr.count) - выводит 0
print(self.imageArr) - при этом выводит полный массив

Как обработать этот момент?
Есть какие-нибудь "умные" статьи по данной теме?

class ProductCartVC: UIViewController {
@IBOutlet weak var cartCV: UICollectionView!

    @IBOutlet weak var priceCartLabel: UILabel!
    @IBOutlet weak var nameCartLabel: UILabel!
    
    @IBOutlet weak var colorButton: UIButton!
    @IBOutlet weak var sizeButton: UIButton!
    @IBOutlet weak var addToBucketButton: UIButton!
    
    @IBOutlet weak var attributesTextView: UITextView!
    @IBOutlet weak var descriptionTextView: UITextView!

    var cartProd: ProductValue?
    
    var imageArr: [String] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        dataProcessing()
        print(imageArr.count)
    }
    
    func dataProcessing() {
        DispatchQueue.main.async {
            for i in (self.cartProd?.productImages)! {
                self.imageArr.append("\(i.imageURL!)")
            }
            self.cartCV.reloadData()
            print(self.imageArr)
        }
    }
    
}

extension ProductCartVC: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return imageArr.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = cartCV.dequeueReusableCell(withReuseIdentifier: "ProductCartCell", for: indexPath) as! ProductCartCell
        
        let imageUrl = URL(string: "<b>url</b>/\(imageArr[indexPath.row])")
        cell.cartImageView.image = UIImage(data: try! Data(contentsOf: imageUrl!))
        
        return cell
    }
    
}
  • Вопрос задан
  • 156 просмотров
Решения вопроса 1
Loriens
@Loriens
iOS Developer
Вообще твой вариант должен работать. Когда ты вызываешь `cartCV.reloadData()`, collection view перерисовывается.

Во-первых, задал ли ты data source и delegate для collection view? В коде этого нет, но может ты сделал это в сториборде. В коде это выглядело бы так:
override func viewDidLoad() {
    super.viewDidLoad()
    cartCV.dataSource = self
    cartCV.delegate = self
    dataProcessing()
    print(imageArr.count)
}


Во-вторых, `cell.cartImageView.image = UIImage(data: try! Data(contentsOf: imageUrl!))` - очень плохо. Это будет выполняться в главном потоке, соответственно, приложение будет заморожено на момент загрузки картинок. Нужно делать это асинхронно. Желательно избегать force unwrapping. Например, так:
DispatchQueue.global().async {
    if let imageUrl = imageUrl,
        let data = try? Data(contentsOf: imageUrl) {
        DispatchQueue.main.async {
            self.cell.cartImageView.image = UIImage(data: data)
        }
    }
}

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

Также есть хорошая либа для асинхронной подгрузки картинок - Kingfisher. C ней подгрузка изображения выглядела бы так:
cell.cartImageView.kf.setImage(with: imageUrl)
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы