0

First - the problem

The problem is that when run the function loadImages(), all of the UIImage objects except for the last one are being returned as nil. To describe in a little more depth: I have 8 urls of images, the first 7 return nil when decoded, the final url is successfully decoded and returned as a UIImage.

I have tried several things to debug:

Changed the amount of urls returned from the api, still the function consistently returns nil for every URL except for the final url in the array returned from the api.

I also changed the API to return an array of only the url that was successfully decoded into a UIImage object, still the function returned nil for each url except the final url, even though they were all the same URL!

I am really lost on this, sleep deprived, and new to swift, so if any help in figuring out what I am missing would be super helpful! Below I have shared all my code, I really hope this is something small I am missing!

Second - my code

Here I have a network request that is going out and getting a list of image urls that are returned in a json array with a wrapper key of "item"

func fetchImageUrls() {
        guard !isLoading else {
            return
        }
        isLoading = true
        let resource = ImageUrlsResource()
        let request = APIRequest(resource: resource)
        self.request = request
        request.execute {[weak self] urls in
            self?.imageUrls = urls ?? []
            self?.isLoading = false
            self?.loadImages()
            
        }
    }

This returns the image urls and formats them to the array of imageUrls properly. The loadImages function is below:

func loadImages() {
        for i in imageUrls {
            let url = URL(string: i.url)
            print(url)
            guard let requestUrl = url else {fatalError()}
            let request = URLRequest(url: requestUrl)
            let imageRequest = ImageRequest(url: request)
            self.imageRequest = imageRequest
            imageRequest.execute { [weak self ] image in
                print(image) // here is returning nill
                let finalImage = FinalImage(id: i.id, image: image ?? nil)
                self?.finalImages.append(finalImage)
            }
        }
    }

Here is the image request class

class ImageRequest {
    let url: URLRequest
    
    init(url: URLRequest) {
        self.url = url
    }
}

extension ImageRequest: NetworkRequest {
    func decode(_ data: Data) -> UIImage? {
        return UIImage(data: data)
    }
    func execute(withCompletion completion: @escaping (UIImage?) -> Void) {
        load(url, withCompletion: completion)
    }
}

And the Network request protocol:

protocol NetworkRequest: AnyObject {
    associatedtype ModelType
    func decode(_ data: Data) -> ModelType?
    func execute(withCompletion completion: @escaping (ModelType?) -> Void)
}

extension NetworkRequest {
    fileprivate func load(_ url: URLRequest, withCompletion completion: @escaping (ModelType?) -> Void) {
        let task = URLSession.shared.dataTask(with: url) {[weak self] (data, response, error) -> Void in
            guard let data = data, let value = self?.decode(data) else {
                DispatchQueue.main.async {
                    completion(nil)
                }
                return
            }
            DispatchQueue.main.async {
                completion(value)
            }
        }
        task.resume()
}
}

Appreciate any help!!

EDIT I added some print statements into the functions at these points

func loadImages() {
        for i in imageUrls {
            let url = URL(string: i.url)
            print(url)
            guard let requestUrl = url else {fatalError()}
            let request = URLRequest(url: requestUrl)
            let imageRequest = ImageRequest(url: request)
            self.imageRequest = imageRequest
            imageRequest.execute { [weak self ] image in
                print(image)
                print("fetching the image")
                let finalImage = FinalImage(id: i.id, image: image ?? nil)
                self?.FinalImages.append(finalImage)
            }
        }
    }


extension ImageRequest: NetworkRequest {
    func decode(_ data: Data) -> UIImage? {
        print("DATA \(data)")
        return UIImage(data: data)
    }
    func execute(withCompletion completion: @escaping (UIImage?) -> Void) {
        load(url, withCompletion: completion)
    }
}

here is the output in the console:

Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
Optional(https://dummyimage.com/455x276.png/cc0000/ffffff)
nil
fetching the image
nil
fetching the image
nil
fetching the image
nil
fetching the image
nil
fetching the image
nil
fetching the image
nil
fetching the image
DATA 1297 bytes
nil
fetching the image
nil
fetching the image
nil
fetching the image
nil
fetching the image
nil
fetching the image
Optional(<UIImage:0x60000057d950 anonymous {455, 276}>)
fetching the image
dilldawg
  • 73
  • 6
  • Inside `decode(_:)` print data. You can see https://stackoverflow.com/questions/39075043/how-to-convert-data-to-hex-string-in-swift how to do it and or also `print("As String: \(String(data: data, encoding: .utf8))")` What's missing: It's unclear if it's that method which return nil, or because `data` before hand is nil. Now, `UIImage()` won't do miracle. If you have a JSON response, that won't do it, or a HTML Text one. `UIImage(data:)` doesn't decode all format. WebP for instance isn't decoded from it, you need a third party lib... – Larme May 04 '21 at 12:23
  • If it's can't be transformed into a String with utf8, and if data output is too long, just show the start and the end. Usually the indicators of the files are seen there. (Start of File, End of File). See there for an example: https://stackoverflow.com/a/58008229/1801544 – Larme May 04 '21 at 12:24
  • @Larme just added the print statements, please see the edit for the output of the code – dilldawg May 04 '21 at 12:34
  • I see only one print of `print("DATA \(data)")`, and I guess that's the working one. So it means there is no data on the other cases? You could print `response` in `dataTask(with:)`? Also, if you go on theses webpages with your web browser, does it work? – Larme May 04 '21 at 13:02

0 Answers0