我无法为 UIImage 进行扩展便利初始化

I can't make extension convenience init for UIImage

我想创建 UIImage(urlString: String?)。当我 运行 这段代码时没有错误,但它不起作用。

extension UIImage {
    convenience init?(urlString: String?) { 
        var imageData = Data()
        guard let urlString = urlString else { return nil}
        guard let url = URL(string: urlString) else { return nil}
        URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }
            guard let response = response as? HTTPURLResponse else {
                print("Empty image response")
                return
            }
            print("HTTP image response code: \(response.statusCode)")
            guard let data = data else {
                print("Empty image data")
                return
            }
            imageData = data
        }.resume()
        self.init(data: imageData)
    }
}

UIImage initializer init(data:) 是一种同步方法。您的 self.init(data: imageData) 方法在异步方法 dataTask 完成其请求并执行其完成处理程序之前被调用。

我的建议是创建一个扩展 URL 的实例方法并向其添加一个完成处理程序:

extension URL {
    func asyncImage(completion: @escaping (UIImage?) -> Void) {
        URLSession.shared.dataTask(with: self) { data, _, _ in
            guard let data = data, let image = UIImage(data: data) else {
                completion(nil)
                return
            }
            completion(image)
        }.resume()
    }
}

用法:

yourURL.asyncImage { image in 
    guard let image = image else { return }
    // use image here
}

另一种选择是扩展 UIImageView,如此 post

我的解决方案:

  • 使用 Data(contentsOf:URL) 从 URL 获取数据,而不是使用 URLSession.dataTask
   extension UIImage {  
    convenience init?(urlString: String) {
        self.init()
        guard let url = URL(string: urlString), let data = try? Data(contentsOf: url) else { return }
        self.init(data: data)
    }
}

您必须调用 self.init(),因为它需要在 return 之前调用 self.init()。 因为这是一个 Failable Initializer,如果你的 URL 是有效的,那么你会从那个 URL 中得到一个图像,否则,你会得到 nil。

如果您想在 URL 无效时使用默认图像,只需将 init() 替换为 init(named:):

   extension UIImage {  
    convenience init?(urlString: String) {
        self.init(named: "YOUR_IMAGE_NAME")
        guard let url = URL(string: urlString), let data = try? Data(contentsOf: url) else { return }
        self.init(data: data)
    }
}