接下來咱們來作硬盤緩存,多張圖片加載,多張圖片緩存的多線程處理。這一節把這些都儘可能處理完,由於這個思路是sdwebimage的思路,確切的說跟名字的 Kingfisher庫,牽扯不是很大。因此儘早把本身的思路所有寫完,好再熟悉的基礎上去讀Kingfisherweb
需求開始:算法
如今我想給硬盤裏存,若是是第一次存儲那麼默認往硬盤裏存,別的狀況就能夠設置一個傳入的參數來告訴到底要不要往硬盤裏存,若是是Objective-c語言的話,咱們要寫兩個方法swift
一個:- (void)storeImage:(UIImage *)image forKey:(NSString *)key 。緩存
一個:- (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk。 第一個方法裏,默認會調用第二個方法 而且傳 YES。: [self storeImage:image forKey:key toDisk:YES];網絡
Swift就不用這麼麻煩多線程
直接聲明可選參數:app
//單例 static let shared = ImageCache() //存儲圖片 func storeImage(url:URL,image:UIImage?,toDisk:Bool?=nil) -> Void { let urlStr = "\(url)" memoryDic?.setValue(image, forKey:urlStr) if toDisk ?? false { //往硬盤裏存 print("存硬盤") } } //. 這裏的 ?=nil,該形參能夠選擇傳入,調用就能夠: // ImageCache.shared.storeImage(url: url, image: self.image!) ImageCache.shared.storeImage(url: url, image: self.image!, toDisk: true)
兩種均可以了直接用了 ,不用報錯。一個函數搞定,不用像OC那樣 多一個參數就要再寫一個方法。這樣寫可能有一些問題,可是慢慢使用才能體會到。 接下來就看看Swift 的 本地沙盒存儲操做語法函數
直接先把方括號改成點語法試試:url
//緩存類------- //這裏不寫:繼承類,它默認會繼承什麼呢? Object? class ImageCache { //聲明及初始化 var memoryDic:NSMutableDictionary? = [:] //單例 static let shared = ImageCache() //存儲圖片 func storeImage(url:URL,image:UIImage?,toDisk:Bool?=nil) -> Void { let urlStr = "\(url)" memoryDic?.setValue(image, forKey:urlStr) if toDisk ?? false { //往硬盤裏存 print("存硬盤") //先建立一個存儲文件夾,後面這個建立代碼寫到該類初始化的時候.注意路徑寫的時候斜槓 let myDirectory:String = NSHomeDirectory() + "/Documents/ImageCache/" let fileManager = FileManager.default //withIntermediateDirectories爲ture表示路徑中間若是有不存在的文件夾都會建立 try! fileManager.createDirectory(atPath: myDirectory, withIntermediateDirectories: true, attributes: nil) //這裏路徑也作一下處理,文件名字作一下md5防止重複,這裏md5路徑寫法有點小問題,到時候參考Kingfisher的算法吧,不過md5自己算法沒問題,只是我用url字符串去作md5不知道穩當不穩當。 let md5FileNamePath = myDirectory + urlStr.md5() fileManager.createFile(atPath: md5FileNamePath, contents: UIImageJPEGRepresentation(image!, 1.0), attributes: nil) } } //取圖片 func imageForKey(url:URL,formDisk:Bool?=nil) ->UIImage? { let urlStr = "\(url)" //若是內存裏有 直接到內存裏拿去顯示 if memoryDic?.allValues.count != 0 && memoryDic?.allValues.count != nil { let image:UIImage = memoryDic!.object(forKey: urlStr) as! UIImage return image } //若是內存裏沒有 再去硬盤裏找 // image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:[self cachePathForKey:key]]]; let myDirectory:String = NSHomeDirectory() + "/Documents/ImageCache/" let md5FileNamePath = myDirectory + urlStr.md5() let img = UIImage.init(contentsOfFile: md5FileNamePath) if (img != nil) { return img } return nil } } //md5 String+MD5.swift import Foundation extension String { func md5() -> String { let str = self.cString(using: String.Encoding.utf8) let strLen = CUnsignedInt(self.lengthOfBytes(using: String.Encoding.utf8)) let digestLen = Int(CC_MD5_DIGEST_LENGTH) let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen) CC_MD5(str!, strLen, result) let hash = NSMutableString() for i in 0 ..< digestLen { hash.appendFormat("%02x", result[i]) } result.deinitialize() return String(format: hash as String) } } #import <CommonCrypto/CommonDigest.h> DIY_SFSCKingfisher-Bridging-Header.h import Foundation import UIKit /// typealias用來爲已存在的類型從新定義名稱的。 typealias ImageView = UIImageView extension ImageView { func sfsc_setImage(url:URL?) -> Void { //------- 這部分代碼,每一個須要網絡圖片的都會用到,因此提取出來 --------- /* guard let語法:guard let 判斷以後 守護 必定有值 若是沒有值 在guard let 的{} 裏 直接返回。 若是須要守護多個值直接在後面跟 逗號 分割開來。 */ guard let url = url else { return } //代碼執行至此 url 必定有值!! if (ImageCache.shared.imageForKey(url: url) != nil) { //若是從內存緩存裏拿到值就直接顯示 而後直接返回,不去加載 self.image = ImageCache.shared.imageForKey(url: url) return } //轉爲data類型 let data : NSData! = NSData(contentsOf: url) //判斷data不爲空,這裏是由於swift對類型要求很嚴,若是未空的話,會崩潰 if data != nil { //賦值圖片 self.image = UIImage.init(data: data as Data, scale: 1) // ImageCache.shared.storeImage(url: url, image: self.image!) ImageCache.shared.storeImage(url: url, image: self.image!, toDisk: true) }else{ // 不然就賦值默認圖片 self.image = UIImage.init(named: "005") } } }