0

I'm trying to use Imgur API on a iOS app, but for some reason I can't get it to work right. I've managed to connect to the API, retrieve it's values and parse to my Decodable Model. In my ViewModel file, if I print the images completion, the console output the received data. But when I try to assign it to an array, where I can use it's values inside my ViewController, the returned array is always empty.

Any clues on what I'm missing here?

Thanks a lot!!

Model:

struct ImgurResponse: Decodable {
    let data: [Image]
}

struct Image: Decodable {
    let title: String
    let link: String
}

Service:

struct Service {
    func fetchImages(_ completion: @escaping ([Image]?) -> Void) {
        guard let url = URL(string: "https://api.imgur.com/3/gallery/search/viral/?q=cats") else { return }
        var request = URLRequest(url: url)
        request.setValue("Client-ID -hidden-", forHTTPHeaderField: "Authorization")
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        let dataTask = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
            
            if let _ = error {
                completion(nil)
                return
            }
            
            if let data = data {
                
                let jsonDecodable = JSONDecoder()
                do {
                    let decode = try jsonDecodable.decode(ImgurResponse.self, from: data)
                    completion(decode.data)
                } catch {
                    print(error)
                    completion(nil)
                }
            }
        }
        dataTask.resume()
    }
}

ViewModel:

class ImageViewModel {
    private let service = Service()
    
    var images = [Image]()
    
    func fetchImages() -> [Image] {
        service.fetchImages { images in
            guard let images = images else { return }
            self.images = images
            
        }
        return images
        
    }
}

completion type

ViewController:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return viewModel.fetchImages().count
    }
Boga
  • 371
  • 3
  • 14
  • We def need to see how you are using the viewModel in your viewController. – Rob C Oct 23 '21 at 22:52
  • @Rob ok, i have edited the question with the call in the ViewController. But even so, in the ViewModel, after I set self.images = images, self.images.count is 0 – Boga Oct 23 '21 at 23:21

1 Answers1

0

You are using @escaping closure which will be executed after the network request is completed, and based on factors like network conditions, it may take a while. So I think calling return viewModel.fetchImages().count directly in numberOfItemsInSection won't work/help.

You need to use images of your viewModel which is initially is an empty array, but when fetchImages() is done, it will fill that array; at this point you need to notify CollectionView to reload data in which this time it shows your viewModel's images. So, your VC code should be sth like this:

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

Let me know if you need more help, I can walk you through that!

  • Hey. Thanks for the help! So, it makes sense what you said, but I've tried and it's still not working... On my ViewController, I have assigned fetchImages() to the empty array images = viewModel.fetchImages(), but the following gives me an nil: print(images.first?.link) – Boga Oct 24 '21 at 01:28