以前写过oc的NSCache缓存和沙盒,最近项目也要用到缓存,而且不只是图片还有视频,如果只是图片,用SDWebImage框架自带的缓存机制就行了,但是加上视频,就得自己写了.
NSCache是内存缓存,沙盒是磁盘文件,NSCache因为在内存里保存,所以每次刚启动app的时候是空的什么都没有,如果要想让NSCache读取到内容,必须先往里面写入数据,从沙盒写入或者从网络读取数据写入.沙盒则是磁盘文件,写入以后只要不删除就一直存在,但是磁盘文件读取速度比NSCache内存缓存慢.
格式如下:
let cache = NSCache<AnyObject, AnyObject>()
cache
需要类遵守协议NSCacheDelegate
cache.delegate = self
//把data数据写入内存缓存NSCache
let cache = NSCache<AnyObject, AnyObject>()
cache.setObject(Data数据 as AnyObject, forKey: "key名字" as AnyObject)
let cache = NSCache()
let data = cache.object(forKey: "key名字" as AnyObject)
cache.removeObject(forKey: "键值" as AnyObject) //删除指定键值的数据
cache.removeAllObjects() //删除全部
即将回收清理cache的时候调用改方法
func cache(_ cache: NSCache, willEvictObject obj: Any) {
print("删除缓存",obj)
}
NSData(data: Data类型数据).write(toFile: 文件路径, atomically: true)
let imageData = NSData(contentsOfFile: 文件路径) as Data?
//
// ViewController.swift
// NSCacheSwiftDemo
//
// Created by tdw on 2021/3/19.
//
import UIKit
class ViewController: UIViewController, NSCacheDelegate {
@IBOutlet weak var imageV: UIImageView!
let urlString = "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2689708464,460600545&fm=26&gp=0.jpg"
var cache = NSCache<AnyObject, AnyObject>()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
cache.delegate = self
}
@IBAction func btnLoadFromNet(_ sender: Any) {
//如果缓存没有图片则网络获取
let session = URLSession.shared //URLSession 也有缓存
let url = NSURL(string: urlString)
let downloadTask = session.dataTask(with: url! as URL, completionHandler: {
[unowned self](data, res, error) in
if error != nil{
print("error=",error)
return
}
guard let data = data else{
print("没取到图片数据")
return
}
//把数据转换为UIImage
//把data数据写入内存缓存NSCache
self.cache.setObject(data as AnyObject, forKey: urlString as AnyObject)
print("写入内存缓存NSCache")
//把data数据写入磁盘沙盒
//获取沙盒路径
let disckCache = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).map(\.path).last
//因为url包含/,但是磁盘缓存文件名不能包含/,所以要去掉/,字符串替换把"/"替换成""
let fileName = urlString.replacingOccurrences(of:"/", with: "")
//拼接图片的全路径
let fullPath = URL(fileURLWithPath: disckCache ?? "").appendingPathComponent(fileName).path
let isSucess = NSData(data: data).write(toFile: fullPath, atomically: true)
if isSucess{
print("写入磁盘沙盒缓存")
}
DispatchQueue.main.async {
//把UIImage用block传出去
print("从网络获取图片")
imageV.image = UIImage(data: data)
}
})
downloadTask.resume()
}
@IBAction func btnLoadFromMemeryCache(_ sender: Any) {
DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {
[unowned self] in
let data = cache.object(forKey: urlString as AnyObject)
if (data != nil){
DispatchQueue.main.async {
imageV.image = UIImage(data: data as! Data)
}
}else{
print("内存缓存中无数据")
}
}
}
@IBAction func btnDeleteImageV(_ sender: Any) {
imageV.image = nil
}
@IBAction func btnDeleteCache(_ sender: Any) {
// cache.removeObject(forKey: urlString as AnyObject)
cache.removeAllObjects()
}
//即将回收清理cache的时候调用改方法
func cache(_ cache: NSCache<AnyObject, AnyObject>, willEvictObject obj: Any) {
print("删除缓存",obj)
}
//写入磁盘缓存
@IBAction func btnWriteDiskClick(_ sender: Any) {
// imageV.image as
}
//读取磁盘沙盒
@IBAction func btnReadDiskClick(_ sender: Any) {
//获取沙盒路径
let disckCache = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).map(\.path).last
//因为url包含/,但是磁盘缓存文件名不能包含/,所以要去掉/,字符串替换把"/"替换成""
let fileName = urlString.replacingOccurrences(of:"/", with: "")
//拼接图片的全路径
let fullPath = URL(fileURLWithPath: disckCache ?? "").appendingPathComponent(fileName).path
//检查磁盘缓存
let imageData = NSData(contentsOfFile: fullPath) as Data?
if (imageData != nil) {
print("磁盘中有数据")
//磁盘数据写入UIImage
imageV.image = UIImage(data: imageData!)
//磁盘数据写入NSCache
cache.setObject(imageData as AnyObject, forKey: urlString as AnyObject)
print("写入内存缓存NSCache")
}else{
print("没从磁盘中取到数据")
}
}
}
运行效果
先实验从网上读取数据,然后写入NSCache内存缓存中,再写入磁盘沙盒中,同时把数据写到UIImageView里面,删除图片后,点击从内存加载数据,可以看到能读出来
2.读取网络数据以后,删掉内存缓存NSCache中的数据,再从NSCahce中读取图片,读取失败
3.内存缓存NSCache中无数据的时候,从磁盘缓存中读取数据写入NSCache中,再从NSCache中读取数据,存入UIImageView 成功
4.app刚启动的时候内存中没有数据NSCache读取不到数据,从沙盒缓存中可以读到数据