代碼+知識點總結
fileprivate struct DataInMemory{ var dataKey:String//數據對應的key var data:Data//數據 var timeStamp:Date//上次訪問數據(存、取、改)的時間 init(dataKey:String,data:Data,timeStamp:Date){//初始化辦法 self.dataKey = dataKey self.data = data self.timeStamp = timeStamp } }1.訪問修飾符:
private:修飾的屬性和辦法只能被本類(構造體)訪問。修飾類(構造體)自身時,經過實驗,效果和fileprivate相反,文件外部可見。
fileprivate:文件外部可見
internal:整個框架、模塊內可見
public:地下,但其它框架、模塊中不可被重寫或承繼
open:地下,且有限制
2.構造體與類相關知識點:(1)構造體是值類型,類是援用類型
(2)當類是let時,可修正其屬性,但構造體是let時,其屬性也不可被修正(構造體是值類型,修正其屬性,會招致新正本的發生,與let相悖)
(3)構造體中的辦法要修正本身屬性時,要加mutating關鍵字修飾(構造體是值類型,修正其屬性,會招致新正本的發生,所以要加mutating告知編譯器處置)
(4)Array Dict Set Int Float Bool String Double等都是構造體
(5)構造體不具有承繼特性
open class ZDataCache
//單例對象,靜態對象+公有初始化辦法 public static let shareCache = ZDataCache() private var _maxDataInMemory:Int//隊列最大長度 //借助計算屬性,完成_maxDataInMemory的存取控制 public var maxDataInMemory:Int{//隊列最大長度 get{ return _maxDataInMemory } set{ if (newValue > 30){ _maxDataInMemory = 30 } else if(newValue <= 0){ _maxDataInMemory = 15 } else{ _maxDataInMemory = newValue } } } private let ioQueue:DispatchQueue //操作隊列 private var memoryCache:[DataInMemory] //內存緩存隊列 private var cleanMemoryTimer:Timer!//緩存自動清算定時器 //本地緩存根目錄地址 private let dataCachePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0].appending("/DataCache/") private init(){ ioQueue = DispatchQueue(label: "zdc.io.queue")//串行隊列,避免多線程競爭 memoryCache = [] _maxDataInMemory = 15 //創立緩存目錄 let fileManager = FileManager.default if !fileManager.fileExists(atPath: dataCachePath) { do{ try fileManager.createDirectory(at: URL(fileURLWithPath: dataCachePath), withIntermediateDirectories: true, attributes: nil) }catch{ NSLog("create cache dir error") } } //活期肅清緩存計時器 //當用weak修飾一個變量時,這個變量自動被零碎聲明為可選型變量 weak var wSelf = self cleanMemoryTimer = Timer(timeInterval: 180, repeats: true, block: { (timer:Timer) in //清算緩存 wSelf!.cleanDataInMemory() }) //不要求計時特別精准,僅在defaultRunLoopMode下任務即可 RunLoop.main.add(cleanMemoryTimer, forMode:RunLoopMode.defaultRunLoopMode) }3.單例的完成:
在swift中完成單例形式非常復雜,只需靜態變量+公有初始化辦法即可。swift在執行時靜態變量初始化時,會自動參加dispatch_once機制保證多線程訪問狀況下的平安
timer在停止初始化的進程中需求完成回調閉包或許指定target及selector,這樣就會不可防止的會訪問到self,但此時編譯器便會報錯,我們在一切成員變量尚未初始化(timer正在初始化中)便訪問了self。
處理的方式是private var cleanMemoryTimer:Timer!
告知編譯器,承諾cleanMemoryTimer在運用時一定是存在初始值的,這樣編譯器就不會再對cleanMemoryTimer的初始化狀況停止反省,其它變量完成初始化後,對象(self)就可以運用了
或許private var cleanMemoryTimer:Timer?
將cleanMemoryTimer聲明為可選型,默許會賦初值nil(不建議運用這種方式)
6.weak與unownedswift與oc一樣,采用基於援用計數的內存管理機制,異樣也存在強弱援用的概念,在oc中我們經過weak描繪一個弱援用關系,在swift中異樣也有weak,它們的作用也完全分歧,weak修飾的指針指向的對象被銷毀後,該指針會被置為nil.但是,swift中引入了可選型的概念,同時還存在var與let的區別。假如一個對象要被賦值為nil,則必需為可選型,同時從指向一個對象到被置為nil,有一個變化進程,所以又必需是一個var,於是就要求weak修飾的是必需是一個可選型var(當用weak修飾一個變量時,這個變量自動就會被聲明為可選型)。但有些狀況下,我們想修飾一個弱援用關系,但是設計上被修飾的指針不是一個可選型或許不是一個var(變量),這個時分就可以用unowned對其停止描繪,unowned異樣描繪一個弱援用關系,但不具有自動置空(nil)的才能,於是也就沒有了可選型及var的要求。不過在運用unowned時要格外小心,防止呈現野指針問題。
/*數據的存儲或更新 在內存緩存中找能否存在key相反的舊數據 存在:更新緩存中對應的數據內容及訪問時間,將對應緩存數據挪到隊尾,將新數據寫到磁盤 不存在:將數據拔出內存緩存隊尾,將數據寫到磁盤 */ public func addDataToCache(key:String,data:Data)->Void{ //guard的運用 guard !key.isEmpty else{ return } guard !data.isEmpty else{ return } let md5Key = md5(str: key) let dataPath = dataCachePath.appending(md5Key) ioQueue.async { //可選型 var dataFindInMemory:DataInMemory? = nil let dataCountInMemory = self.memoryCache.count for i in 0..<dataCountInMemory{ var dataInMemory = self.memoryCache[i] if(dataInMemory.dataKey == md5Key){ //更新數據,數據有能夠發生變化 dataInMemory.data = data //更新訪問時間 dataInMemory.timeStamp = Date() dataFindInMemory = dataInMemory self.memoryCache.remove(at: i) break } } //if的可選型解包 if let dataFindInMemory = dataFindInMemory{ self.memoryCache.append(dataFindInMemory) } else{ self.insertDataToMemory(data: data, key: md5Key) } do{ try data.write(to: URL(fileURLWithPath: dataPath), options: Data.WritingOptions.atomicWrite) }catch{ NSLog("write error") } } }7.閉包中為什麼要加self.
在同一個類外部,當我們想要訪問類的其它成員變量或辦法時只需直接調用即可,如
let md5Key = md5(str: key)//調用md5加密辦法
let dataPath = dataCachePath.appending(md5Key)//運用dataCachePath屬性但是,即使是在類外部,假如我們在一個閉包中去直接訪問成員變量或辦法,編譯器是會報錯的,如 /*數據讀取 在內存緩存中找能否存在key相反的數據 存在:更新緩存中對應的數據的訪問時間,將對應緩存數據挪到隊尾,前往內存緩存中數據 不存在:從磁盤讀取數據,將數據拔出內存緩存隊尾 */ public func readDataFromCache(key:String)->Data?{ guard !key.isEmpty else{ return nil } let md5Key = md5(str: key) let dataPath = dataCachePath.appending(md5Key) var data:Data? = nil let group = DispatchGroup() var tempDataInMemory:DataInMemory? = nil ioQueue.async(group: group){ group.enter() let dataCountInMemory = self.memoryCache.count for i in 0..<dataCountInMemory{ var dataInMemory = self.memoryCache[i] if(dataInMemory.dataKey == md5Key){ tempDataInMemory = dataInMemory data = dataInMemory.data dataInMemory.timeStamp = Date() self.memoryCache.remove(at: i) break } } if let tempDataInMemory = tempDataInMemory{ self.memoryCache.append(tempDataInMemory) } else { do{ try data = Data(contentsOf: URL(fileURLWithPath: dataPath)) self.insertDataToMemory(data: data!, key: md5Key) }catch{ NSLog("read error") } } group.leave() } group.wait() return data }
/*數據刪除 在內存緩存中找能否存在key相反的數據 存在:刪除內存緩存中對應數據,刪除磁盤數據 不存在:刪除磁盤數據 */ public func removeDataFromCache(key:String)->Void{ guard !key.isEmpty else{ return } let md5Key = md5(str: key) let dataPath = dataCachePath.appending(md5Key) ioQueue.async { let dataCountInMemory = self.memoryCache.count for i in 0..<dataCountInMemory{ let dataInMemory = self.memoryCache[i] if (dataInMemory.dataKey == md5Key){ self.memoryCache.remove(at: i) break } } do{ try FileManager.default.removeItem(at: URL(fileURLWithPath: dataPath)) }catch{ NSLog("remove error") } } }
/*在內存緩存中參加一條新數據 緩存隊列能否已滿? 是:移除隊頭最老數據,在隊尾參加一條新數據 否:在隊尾參加一條新數據 */ private func insertDataToMemory(data:Data,key:String)->Void{ let dataInMemory = DataInMemory(dataKey: key, data: data, timeStamp: Date()) let dataCountInMemory = memoryCache.count if(dataCountInMemory < maxDataInMemory){ memoryCache.append(dataInMemory) } else{ memoryCache.remove(at: 0) memoryCache.append(dataInMemory) } }
/*緩存清算 從隊尾開端遍歷,直到找到一條上次訪問的時間超越180秒的數據 從緩存隊列中刪除這條及這條之前的一切數據(隊列中數據都是依照訪問時間,從遠到近陳列好的) */ private func cleanDataInMemory()->Void{ let dataCountInMemory = memoryCache.count var dirtyDataIndex:Int? = nil let currentDate = Date() for i in (0..<dataCountInMemory).reversed(){ let dataInMemory = memoryCache[i] if(currentDate.timeIntervalSince(dataInMemory.timeStamp) >= 180){ dirtyDataIndex = i } } if let dirtyDataIndex = dirtyDataIndex{ memoryCache.removeSubrange(0...dirtyDataIndex) } }
//md5加密 private func md5(str:String)->String{ let cStr = str.cString(using: String.Encoding.utf8) let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 16) CC_MD5(cStr!,(CC_LONG)(strlen(cStr!)), buffer) let md5String = NSMutableString() for i in 0 ..< 16{ md5String.appendFormat("%02x", buffer[i]) } free(buffer) return md5String as String }
都是練習代碼,很多中央不是很嚴謹,同時也是第一個swift理論,如有了解或完成不對的中央,歡送指正
【Swift3.0學習理論】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!