簡體   English   中英

我正在嘗試為 UIImageView 添加擴展以異步加載圖像,但會引發錯誤。 Swift

[英]I'm trying to add an extension for UIImageView to load the image asynchronously, but it throws an error. Swift

由於聲明了一個常量,第 3 行出錯,為什么會發生這種情況? 錯誤:擴展不得包含存儲的屬性代碼:

extension UIImageView {

    let imageCache = NSCache<NSString, UIImage>() //error
    
        func imageFromServerURL(_ URLString: String, placeHolder: UIImage?) {

        self.image = nil
        //If imageurl's imagename has space then this line going to work for this
        let imageServerUrl = URLString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
        if let cachedImage = imageCache.object(forKey: NSString(string: imageServerUrl)) {
            self.image = cachedImage
            return
        }

        if let url = URL(string: imageServerUrl) {
            URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in

                //print("RESPONSE FROM API: \(response)")
                if error != nil {
                    print("ERROR LOADING IMAGES FROM URL: \(String(describing: error))")
                    DispatchQueue.main.async {
                        self.image = placeHolder
                    }
                    return
                }
                DispatchQueue.main.async {
                    if let data = data {
                        if let downloadedImage = UIImage(data: data) {
                            self.imageCache.setObject(downloadedImage, forKey: NSString(string: imageServerUrl))
                            self.image = downloadedImage
                        }
                    }
                }
            }).resume()
        }
    }
}

我使用了這段代碼,但不明白為什么它不起作用: Swift async load image

是的,擴展可能不會添加存儲屬性。 這種方式可能是最好的,這樣您的類就不會因為庫通過添加一些您很可能不感興趣的附加信息來擴展您的類而增加大小。

但是在您的情況下,您可能甚至不想擁有存儲的財產。 您編碼的方式意味着您的每個UIImageView實例都將擁有自己的緩存。 因此,例如,顯示每個單元格的圖像視圖的表格視圖意味着每個可見單元格的緩存,這會導致多次下載同一圖像而不是共享它。

在您的情況下,這個問題的最佳解決方案可能是使其成為 static:

extension UIImageView {

    private static let imageCache = NSCache<NSString, UIImage>()
    private var imageCache: NSCache<NSString, UIImage> { UIImageView.imageCache }
    
    func imageFromServerURL(_ URLString: String, placeHolder: UIImage?) {
        self.image = nil
        // If image url's image name has space then this line going to work for this
        let imageServerUrl = URLString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
        if let cachedImage = imageCache.object(forKey: NSString(string: imageServerUrl)) {
            self.image = cachedImage
            return
        }

        if let url = URL(string: imageServerUrl) {
            URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
                //print("RESPONSE FROM API: \(response)")
                if error != nil {
                    print("ERROR LOADING IMAGES FROM URL: \(String(describing: error))")
                    DispatchQueue.main.async {
                        self.image = placeHolder
                    }
                    return
                }
                DispatchQueue.main.async {
                    if let data = data {
                        if let downloadedImage = UIImage(data: data) {
                            self.imageCache.setObject(downloadedImage, forKey: NSString(string: imageServerUrl))
                            self.image = downloadedImage
                        }
                    }
                }
            }).resume()
        }
    }
    
}

除了您的問題,您應該知道您嘗試解決的任務可能不像您提供的代碼那么簡單。 我在您的代碼中看到至少兩個主要問題:

  1. 當快速多次調用此方法時,您可能會遇到第一次調用將比第二次調用更晚下載圖像的競爭條件。 在這種情況下,將顯示第一個圖像而不是第二個(最后一個)圖像
  2. 當為同一個圖像多次調用此方法時,您將多次在同一個資源上啟動下載(相同的圖像顯示在屏幕的 2 個位置將下載兩次)

然后可能還有更多。 例如,這一切都在 memory 中。 在 memory 耗盡之前,您預計可以緩存多少圖像? 也許最好將其移動到某個文件系統中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM