【发布时间】:2019-09-29 19:12:12
【问题描述】:
我在这里找到了有关如何同时下载图像而不会损坏的这段代码,
func loadImageRobsAnswer(with urlString: String?) {
// cancel prior task, if any
weak var oldTask = currentTask
currentTask = nil
oldTask?.cancel()
// reset imageview's image
self.image = nil
// allow supplying of `nil` to remove old image and then return immediately
guard let urlString = urlString else { return }
// check cache
if let cachedImage = DataCache.shared.object(forKey: urlString) {
self.transition(toImage: cachedImage as? UIImage)
//self.image = cachedImage
return
}
// download
let url = URL(string: urlString)!
currentURL = url
let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
self?.currentTask = nil
if let error = error {
if (error as NSError).domain == NSURLErrorDomain && (error as NSError).code == NSURLErrorCancelled {
return
}
print(error)
return
}
guard let data = data, let downloadedImage = UIImage(data: data) else {
print("unable to extract image")
return
}
DataCache.shared.saveObject(object: downloadedImage, forKey: urlString)
if url == self?.currentURL {
DispatchQueue.main.async {
self?.transition(toImage: downloadedImage)
}
}
}
// save and start new task
currentTask = task
task.resume()
}
但是,此代码用于 UIImageView 扩展,
public extension UIImageView {
private static var taskKey = 0
private static var urlKey = 0
private var currentTask: URLSessionTask? {
get { return objc_getAssociatedObject(self, &UIImageView.taskKey) as? URLSessionTask }
set { objc_setAssociatedObject(self, &UIImageView.taskKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
}
private var currentURL: URL? {
get { return objc_getAssociatedObject(self, &UIImageView.urlKey) as? URL }
set { objc_setAssociatedObject(self, &UIImageView.urlKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
}}}
这就是我尝试使此代码动态化的方式,因此它不会仅限于 UIImageView,而是可以用于下载多个资源。
class DataRequest {
private static var taskKey = 0
private static var urlKey = 0
static let shared = DataRequest()
typealias ImageDataCompletion = (_ image: UIImage?, _ error: Error? ) -> Void
private var currentTask: URLSessionTask? {
get { return objc_getAssociatedObject(self, &DataRequest.taskKey) as? URLSessionTask }
set { objc_setAssociatedObject(self, &DataRequest.taskKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
}
private var currentURL: URL? {
get { return objc_getAssociatedObject(self, &DataRequest.urlKey) as? URL }
set { objc_setAssociatedObject(self, &DataRequest.urlKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
}
func downloadImage(with urlString: String?, completion: @escaping ImageDataCompletion) {
weak var oldTask = currentTask
currentTask = nil
oldTask?.cancel()
guard let urlString = urlString else { return }
if let cachedImage = DataCache.shared.object(forKey: urlString) {
DispatchQueue.main.async {
completion(cachedImage as? UIImage ,nil)
}
// self.transition(toImage: cachedImage as? UIImage)
//self.image = cachedImage
return
}
// download
let url = URL(string: urlString)!
currentURL = url
let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
self?.currentTask = nil
if let error = error {
if (error as NSError).domain == NSURLErrorDomain && (error as NSError).code == NSURLErrorCancelled {
return
}
completion(nil,nil)
return
}
guard let data = data, let downloadedImage = UIImage(data: data) else {
print("unable to extract image")
return
}
DataCache.shared.saveObject(object: downloadedImage, forKey: urlString)
if url == self?.currentURL {
DispatchQueue.main.async {
completion(downloadedImage ,nil)
}
}
}
// save and start new task
currentTask = task
task.resume()
}
所以我现在可以在这样的 UIImageview 扩展中使用它
extension UIImageView {
func setImage(url: String?) {
self.image = nil
DataRequest.shared.downloadImage(with: url) { (image, error) in
DispatchQueue.main.async {
self.image = image
}
}
}
}
总结在 UICollectionView 上使用我的方法是在单元格中显示错误的图像并重复,我该如何防止这种情况发生?
【问题讨论】:
标签: ios swift urlsession nsurlsessiondatatask