R
R
RememberMeOne2020-02-08 23:22:48
Swift
RememberMeOne, 2020-02-08 23:22:48

How to solve the problem with threads when processing data?

Hello colleagues.
Faced a problem with displaying data.
There is VC in it CollectionVC is implemented.

It is necessary to display in CollectionVC several pictures uploaded via URL.

The problem itself: the dataProcessing() function iterates over the data and pulls out a string with which the image is subsequently loaded. Using the function, I fill the array, but as I understand it, the data does not have time to reach the addressee before the interface is loaded, and nothing is displayed in CollectionVC.
print(imageArr.count) - prints 0
print(self.imageArr) - prints full array

How to handle this moment?
Are there any "smart" articles on this topic?

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
    }
    
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
Vladislav Markov, 2020-02-09
@RememberMeOne

Generally your variant should work. When you call `cartCV.reloadData()`, the collection view is redrawn.
First, have you set the data source and delegate for the collection view? This is not in the code, but maybe you did it in the storyboard. In code it would look like this:

override func viewDidLoad() {
    super.viewDidLoad()
    cartCV.dataSource = self
    cartCV.delegate = self
    dataProcessing()
    print(imageArr.count)
}

Second, `cell.cartImageView.image = UIImage(data: try! Data(contentsOf: imageUrl!))` is very bad. This will be executed in the main thread, so the application will be frozen while the images are loading. You need to do it asynchronously. It is advisable to avoid force unwrapping. For example, like this:
DispatchQueue.global().async {
    if let imageUrl = imageUrl,
        let data = try? Data(contentsOf: imageUrl) {
        DispatchQueue.main.async {
            self.cell.cartImageView.image = UIImage(data: data)
        }
    }
}

This solution is a crutch, but I'm just writing as an example. Loading data should not be in the main thread, but updating the image in the main one.
There is also a good lib for loading images asynchronously - Kingfisher . With it, the image loading would look like this:
cell.cartImageView.kf.setImage(with: imageUrl)

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question