Home > Net >  loading images from API in collectionview ios
loading images from API in collectionview ios

Time:08-25

This is my API: http://swaminarayanwales.org.uk/DailyDarshan/ExportJsonV2.php?sMandir=Nairobi-Temple&Target=real&sm=sm

I AM trying to get images from API in collection view

import UIKit

    struct Images: Decodable {
         let images = [imageUrl]()
     }

     struct imageUrl: Decodable {
        let imageloc: String
      }

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

@IBOutlet weak var CollectionView: UICollectionView!
var imageses = [Images]()
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    callAPI()
}

func callAPI(){
    guard let url = URL(string: "http://swaminarayanwales.org.uk/DailyDarshan/ExportJsonV2.php?sMandir=Nairobi-Temple&Target=real&sm=sm") else{
        return
    }
    let task = URLSession.shared.dataTask(with: url){ data, response, error in
        if let data = data, let string = String(data: data, encoding: .utf8){
            print(string)
        }
    }
    task.resume()
}

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     let url = URL(string: "http://swaminarayanwales.org.uk/DailyDarshan/ExportJsonV2.php?sMandir=Nairobi-Temple&Target=real&sm=sm )")
    URLSession.shared.dataTask(with: url!) { (data, response, error) in
        guard let data = data else { return }
        do{
            let jsonData =  try JSONDecoder().decode([Images].self, from: data)
            if let imgUrl = URL(string: jsonData[indexPath.row].images[indexPath.row].imageloc){
                if let data = try? Data(contentsOf: imgUrl){
                    cell.imageView.image = UIImage(data: data)
                }
            }
            DispatchQueue.main.async {
                self.collectionView.reloadData()
            }
        }
        catch{
            print("error while decoding")
        }
    }.resume()
    return cell
}

}

i don't have Xib for collection cell

 import UIKit

 class CollectionViewCell: UICollectionViewCell {

     @IBOutlet weak var ImageView: UIImageView!
 }

when i try to get response from API it gives me proper op in log file so API has no problem

but i am not able to load image response in collection view

i made 2 structure and second structure is used in first as array because in API images is in array form

when i run project i get no output.....

CodePudding user response:

There are a few serious design mistakes in your code.

First of all, never load images synchronously in cellForRow/Item. Another mistake is that the root object of the JSON is a dictionary so it's Images.self

But first things first.

Give the structs more meaningful names and decode the url string directly as URL

struct ImageData : Decodable {
    let images : [Location]
}
struct Location: Decodable {
    let imageloc: URL
}

To load the images asynchronously and not inside the collection view datasource methods use DispatchGroup to load the images one by one and notify when all images are available.

Declare the data source array as an array of UIImage

var images = [UIImage]()

and replace callAPI() with

func callAPI(){
    let url = URL(string: "http://swaminarayanwales.org.uk/DailyDarshan/ExportJsonV2.php?sMandir=Nairobi-Temple&Target=real&sm=sm")!
    
    let task = URLSession.shared.dataTask(with: url){ data, response, error in
        if let error = error { print(error); return }
        do {
            let imageData = try JSONDecoder().decode(ImageData.self, from: data!)
            let imageURLs = imageData.images.map(\.imageloc)
            let group = DispatchGroup()
            for imageURL in imageURLs {
                group.enter()
                URLSession.shared.dataTask(with: imageURL){ data, response, error in
                    defer{ group.leave() }
                    if let error = error { print(error); return }
                    if let image = UIImage(data: data!) {
                        self.images.append(image)
                    }
                }.resume()
                
            }
            group.notify(queue: .main) {
                self.collectionView.reloadData()
            }
        } catch {
            print(error)
        }
    }
    task.resume()
}

Now the collection view datasource methods are simply

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

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionViewCell
    cell.imageView.image = images[indexPath.row]
    return cell
}

Don't forget to set the identifier of the collection view cell to Cell in Interface Builder.

CodePudding user response:

There are two issues in your code

  1. When you are getting response from the API, you need to populate the array "imageData".

  2. Then you need to reload the collectionView by calling reloadData() method.

  • Related