代碼+知識點總結
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學習理論】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!