0

I am using the Flickr api to retrieve images based on a search using the following code. The function sends the image id to the endpoint and returns an object which I parse to get a specific url for said image. I get the response that I want but I am trying to get all the image urls which are in item.source and add them to an array. I have tried returning a array but the compiler complains this cannot be done as it's a non-void return from a void method despite me setting [String] as the return. How can I get the list of item.source as an array to be used outside of getURLImages()? Alternatively, I have created urlsList as below, and tried to append the item.source to this but this always prints as empty. For context, I am planning to create a UICollectionView to display said images/urls.

UPDATE

Below is the function from class A that calls getURLImages from class B:

 let result = try JSONDecoder().decode(Response.self, from: data)
  
 if (result.stat == "ok"){
     for urls in result.photos!.photo {           
         DispatchQueue.main.async {
             GetImageInfo().getURLImages(photoId: urls.id) { urlsList in
                  print("Received \(urlsList)")
              }
         }
      }
 }

Below is the function from class B:

let result = try JSONDecoder().decode(Response.self, from: data)
var urlList = [String]()
for item in result.sizes!.size {
    DispatchQueue.main.async {
        if (item.label == "Square"){
            urlList.append(item.source)
                            
        }
    }
 }
 completion(urlList)

How can I access the urlsList property outside the scope of the functions so that it can be implemented into a UICollectionView

1 Answer 1

1

You cannot directly return a value for a function from a closure. You will have to use completion handler closure for this.


Example:

func getURLImages(photoId: String, completion: @escaping ([String]) -> Void) {
    ...
    // Call completion handler when you generate your [String] response
    completion(yourImageURLs)
    ...
}

And use it like this:

let urls = [String]()

getURLImages(photoId: "some id") { [weak self] imageURLs in
    guard let self = self else { return }

    print("Received some \(imageURLs)"
    self.urls = imageURLs
    self.updateCollectionViewOrSomething()
}

func updateCollectionViewOrSomething() {
    self.collectionView.reloadData()
}
Sign up to request clarification or add additional context in comments.

9 Comments

Inside the function, what would I replace yourImageURLS with? They're currently obtained once looping through the json response and where a specific key,value occurs. Would I do completion(urlsList)?
You could create a local [String] array inside your closure before starting your for loop and populate that array instead of urlsList, then use that array inside a completion instead. That way you could easily move your getURLImages somewhere else without breaking your code that much.
And to even more isolate your function from outside you could improve your parameters list: getURLImages(photoId: String, config: AppConfig = AppConfig(), completion: ...)
This way you could move getURLImages into its separate file or anywhere else in the codebase without breaking your existing code.
By the way, completion handler should be called when you FINISH gathering your urls, so, outside the for loop.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.