0

I'm trying to add an image from URL to UIImageView. I get no errors but nothing is showing on the screen.

What am I doing wrong here?

I used the same approach with images from .xcassets and it worked fine, but it's not working from a remote url.

Here are my files:

RelatedCollectionViewCell.swift

class RelatedCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var related: UIImageView!

}

ViewController.swift

var images = [AnyObject]()

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return images.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    do {
        try images.append(UIImage(data:  Data(contentsOf: URL(string:"https://i.ytimg.com/vi/kWxHV9jkwSA/hqdefault.jpg")!))!)
    } catch {
        print(error)
    }

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RelatedCollectionViewCell", for: indexPath) as! RelatedCollectionViewCell

    cell.related.image = images[indexPath.row] as? UIImage

    return cell
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
M1X
  • 4,971
  • 10
  • 61
  • 123

2 Answers2

0

This is not working because at the moment that collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) is executed there are zero items inside the images array. (Because you load them from a URL which takes at least a little time).

So you have to make it reload after you finished downloading the image by adding:

collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    ....
    self.reloadData()
}

Or you could of course give it a fixed amount of Items in a section if you know this amount on forehand:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
   return 5//whatever amount
}

Of course it would be better to load the images asynchronously to stop it from freezing your app when no internet connection is present, but this was not part of the question.

Eric
  • 1,210
  • 8
  • 25
  • How. can I do that please? Can you show me a link or smth.? Or at least what does it take ? – M1X Sep 02 '17 at 21:48
  • Calling `self.reloadData()` inside `cellForItemAt...` ? Shouldn't do that. The correct answer would be to use DispatchQueue.main.async instead. – nathan Sep 02 '17 at 21:48
  • @rexhin The question linked above, marked as "Possible dupe of" has all the information you'll need. – nathan Sep 02 '17 at 21:49
  • 1
    It would be indeed better to use asynchronous loading, but as the question was what was going wrong I thought to post it like this – Eric Sep 02 '17 at 21:50
  • Yes I want to use asynchronous loading. Can you tell me what do I need to change or maybe a link? @Eric – M1X Sep 02 '17 at 21:50
  • Your answer will probably solve one problem but the OP will ask (most likely) about "UI freezing"/etc. I think a complete answer should include both fixes as you mentioned in your original answer. – nathan Sep 02 '17 at 21:52
  • 1
    just use the UIImageView extension in the duplicate question – Leo Dabus Sep 02 '17 at 21:52
  • The link @nathan provided explains all about loading it in the background(asynchronously). If you just execute a function with that at the viewDidLoad() function and load the Collectionview from the completion of that internet task you should be good – Eric Sep 02 '17 at 21:52
  • I can not access `@IBOutlet weak var related: UIImageView!` which is located in another file `RelatedCollectionViewCell.swift` inside my `ViewController` – M1X Sep 02 '17 at 22:10
  • To access things from one class in another with networking you have to use a **callback**. So when calling the networking function you pass the instance of the viewcontroller which calls the networking function(self) as an argument. Then inside the networking function you can access everything from the viewcontroller class by getting them from the callback argument. – Eric Sep 03 '17 at 16:08
0

This is because your array images.count = 0 in first loading

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return images.count
}

because Images array is empty

and if your number of Item is 0 , your app is not enter in func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell.