制作一个依赖于网络的构造函数 swift(从 url 制作 UIImage)



基于 https://stackoverflow.com/a/27712427/4166655,我发现我可以用这段代码创建一个UIImage

func downloadImage(from url: URL) {
print("Download Started")
getData(from: url) { data, response, error in
guard let data = data, error == nil else { return }
print(response?.suggestedFilename ?? url.lastPathComponent)
print("Download Finished")
DispatchQueue.main.async() {
self.imageView.image = UIImage(data: data)
}
}
}

我看到许多包含此代码的UIImageView扩展,但我想知道我是否可以将其作为UIImage的直接初始化。

我想出了这个——

extension UIImage {
convenience init?(url: String) {
guard let urlObj = URL(string: url) else { return nil }
self.init(url: urlObj)
}
convenience init?(url: URL) {
let semaphore = DispatchSemaphore(value: 0)
var imageData: Data? = nil
URLSession.shared.dataTask(with: url) { (data, response, err) in
// breakpoint put here
guard let data = data else { return }
imageData = data
semaphore.signal()
}
semaphore.wait()
if let data = imageData {
self.init(data: data)
} else {
return nil
}
}
}

但这只是超时,我的断点(在代码中注明(永远不会触发。

这种方法有什么问题?

我的断点(在代码中注明(永远不会触发

因为您从未真正启动过 URLSession 数据任务(通过告诉它resume

(:
URLSession.shared.dataTask(with: url) { (data, response, err) in
// whatever
}.resume() // <-- this is what's missing

但是,您在此处的整个方法是错误的:

  • 不能在初始值设定项期间"暂停",也不能在阻止主队列时"等待"某些异步操作完成。您需要立即返回初始化的实例。

  • 如果这不是初始值设定项,并且发生在后台队列上,则"等待"另一个后台操作完成的最佳方法是使用 DispatchQueue。

最新更新