- Object-c的SDWebImage,swift的Kingfisher,功能强大,内容复杂,可谓开发之首选,但有时候,我们需要的仅仅是下载图片,功能不用太过强大,比如我在模仿百度糯米,自己封装,省却了导入框架的麻烦。
- 首先,复习一下多图片下载的知识点。
- 下载操作异步进行;
- 首先从内存缓存中取图片,有就显示;
- 如果内存缓存没有图片,到沙盒Cache中取,有就显示并且保存到内存缓存;
- 如果沙盒Cache中没有,下载图片,成功后回到主线程显示图片,并保存到内存盒沙盒。
- 以UIButton为例,接口模仿SDWebImage,给UIButton添加分类。
func sin_setImageWithUrl(url:String) {
sin_setImageWithUrl(url: url, placeholderImage: UIImage())
}
func sin_setImageWithUrl(url:String,placeholderImage:UIImage) {
setImage(placeholderImage, for: UIControlState.normal)
SINImageDownloaderManager.shared.downloadImage(url: url) { (image) in
self.setImage(image, for: UIControlState.normal)
}
}
SINImageDownloaderManager:下载类,实现核心代码
// 单粒
static let shared = SINImageDownloaderManager()
// 内存缓存图片,根据图片操作
var cacheImages:Dictionary<String, Any> = [:]
// 保存回调闭包
var completionDict = [String:(image:UIImage) -> Void]()
// 发现了swift的bug,当定义闭包时, var completion = (image:UIImage) -> Void(),这种写法到赋值后极易引发xcode代码颜色变黑,久不变回,望大神指出这种写法的错误。
// 队列
var queue:OperationQueue = {
let queue = OperationQueue.init()
queue.maxConcurrentOperationCount = 3
return queue
}()
func downloadImage(url:String,completion:@escaping (_ image:UIImage)->Void) {
completionDict[url] = completion
// 从内存缓存中取图片
let cacheImage = cacheImages[url] as! UIImage?
if cacheImage != nil {
if completionDict[url] != nil {
completionDict[url]!(cacheImage!)
return
}
}
// 从沙盒cache中获取图片
let cachePath = url.cacheDir()
print(cachePath)
let sanboxData = NSData.init(contentsOfFile: cachePath)
if (sanboxData != nil) {
let sandboxImage = UIImage.init(data: sanboxData! as Data)
// 保存到内存缓存
cacheImages[url] = sandboxImage
// 回调
if completionDict[url] != nil {
completionDict[url]!(sandboxImage!)
return
}
}
// 内存和沙盒中均没有图片,开始下载
queue.addOperation {
let downloadData = NSData.init(contentsOf: URL.init(string: url)!)
let downloadImage = UIImage.init(data: downloadData! as Data)
// 回主线程
OperationQueue.main.addOperation {
// 回调
if self.completionDict[url] != nil {
self.completionDict[url]!(downloadImage!)
}
// 保存到内存
self.cacheImages[url] = downloadImage
// 保存到沙盒
downloadData?.write(to: URL.init(fileURLWithPath: cachePath), atomically: true)
}
}
}