swiftxcode11setvaluenscachensunknownkeyexception

Set value to an cached image ends in crash


I am downloading an image and add it to my cache. That works fine, but when I want to add a value to my downloaded image in the cache, my code returns the error "Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<NSCache 0x600001cfa3c0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key XXX".

 let cache = NSCache<NSString, UIImage>()

 func downloadImage(withURL url:URL, completion: @escaping (_ image:UIImage?)->()) {
        let dataTask = URLSession.shared.dataTask(with: url) { data, responseURL, error in

            var downloadedImage:UIImage?

            if let data = data {
                downloadedImage = UIImage(data: data)
                print("downloadedImage")
            }
            DispatchQueue.main.async {
                completion(downloadedImage)
            }
            if downloadedImage != nil {

                let date = Date() // calling the date
                var calendar = Calendar.current // calling the calendar
                if let timeZone = TimeZone(identifier: "GMT-4") { 
                    calendar.timeZone = timeZone
                }
                let day = calendar.component(.day, from: date)
                
                self.cache.setObject(downloadedImage!, forKey: url.absoluteString as NSString)
                self.cache.setValue(day, forKey: url.absoluteString) // this line runs into an error
            }
            
        }
        dataTask.resume()
    }

Solution

  • The error occurs because Int is not a subclass of an NSObject

    But there are two other serious issues.

    1. The cache is declared as <NSString, UIImage> so the value must be an UIImage, however day is Int.
    2. It makes no sense to overwrite the image with the integer anyway

    You could append the day value to the URL string

    let day = calendar.component(.day, from: date)
    let key = "\(url.absoluteString)-\(day)"            
    self.cache.setObject(downloadedImage!, forKey: key as NSString)