直接下载并缓存图片
为了了解新知识,下面的代码分为没有进行封装过的版本和封装过得版本
未封装版
首先需要一个数据模型,数据模型建立需要的属性在编写代码的时候按需要具体添加
- dataModel
import UIKit
class DataModel: NSObject {
var name = ""
var icon = ""
var download = ""
init(dict:NSDictionary){
super.init()
self.name = dict["name"] as! String
self.icon = dict["icon"] as! String
self.download = dict["download"] as! String
}
}
-
ViewController
其中的cell是通过Xib自定义的
import UIKit
///图片缓存目录
let imageCache_Path = NSHomeDirectory() + "/Library/Caches/imageCache"
class ViewController: UITableViewController {
//MARK: - 属性
//1.数据源数组
lazy var dataArray:[DataModel] = {
return self.getData()
}()
//2.队列任务
lazy var queue:NSOperationQueue = {
var tQueue = NSOperationQueue()
//设置最大并发数
tQueue.maxConcurrentOperationCount = 3
return tQueue
}()
//3.图片缓存
//NSCache是一种和字典一样的容器。通过键值对的形式去存储数据。和字典相比,NSCache在程序接收到内存警告的时候会自动删除自己存储的数据
lazy var imageCach:NSCache = {
return NSCache()
}()
//4.任务缓存
lazy var oprationCache:NSMutableDictionary = {
return NSMutableDictionary()
}()
//MARK: - 生命周期
override func viewDidLoad() {
super.viewDidLoad()
//注册cell
self.tableView.registerNib(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "cell")
//设置行高
self.tableView.rowHeight = 120
//在沙盒目录下创建缓存图片的文件夹
//在制定目录下创建一个文件夹
//参数1:需要创建文件夹的目录
//参数2:是否创建中间目录(保险起见填true)
//参数3:文件夹的属性(nil -> 默认属性)
do{
try NSFileManager.defaultManager().createDirectoryAtPath(imageCache_Path, withIntermediateDirectories: true, attributes: nil)
}catch{
print("文件夹已经存在")
}
}
//MARK: - 内存警告的时候自动调用
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
//删除缓存
self.oprationCache.removeAllObjects()//删除字典里面的数据(不一定删除完)
}
}
extension ViewController{
func getData() -> [DataModel]{
var tempArray = [DataModel]()
//1.获取plist路径
let path = NSBundle.mainBundle().pathForResource("model.plist", ofType: nil)
//2.拿到plist文件中的数组
let plistArray = NSArray(contentsOfFile: path!)
//3.遍历数组拿到所有字典
for item in plistArray!{
let dict = item as! NSDictionary
//4.根据字典创建对应的字典模型
let model = DataModel(dict: dict)
//5.将模型保存到数组中
tempArray.append(model)
}
return tempArray
}
}
//MARK: - 协议方法
extension ViewController{
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//1.创建cell
let cell = tableView.dequeueReusableCellWithIdentifier("cell",forIndexPath: indexPath) as! TableViewCell
//2.刷新数据
let model = self.dataArray[indexPath.row]
cell.nameLabel.text = model.name
cell.downloadLabel.text = model.download
//a.判断程序缓存中是否已经有了对应的图片
if self.imageCach.objectForKey(model.icon) != nil{
cell.iconImageView.image = self.imageCach.objectForKey(model.icon) as? UIImage
return cell
}else{
//b.查看是否有本地缓存
//获取当前cell对应数据中的图片名字
let fielName = (model.icon as NSString).lastPathComponent
//拼接文件对应的路径
let path = imageCache_Path + "/" + fielName
//获取本地文件
let data = NSData(contentsOfFile: path)
//判断是否找到了对应的本地图片
if data != nil{
let image = UIImage(data: data!)
//保存到程序的缓存中
self.imageCach.setObject(image!, forKey: model.icon)
//显示图片
cell.iconImageView.image = image
//print("获取本地数据")
return cell
}
//c.如果本地缓存没有再做网络请求
//图片没有加载出来就显示站位图
cell.iconImageView.image = UIImage(named: "user_default.png")
//异步下载图片
self.downloadImage(indexPath)
}
//3.返回cell
return cell
}
}
//MARK: - 图片异步下载
extension ViewController{
func downloadImage(indexPath:NSIndexPath){
let model = self.dataArray[indexPath.row]
//1.!!!判断当前下载任务是否已经创建过!!!(避免网络不好的情况下重复创建同一个下载任务)
//如果任务缓存里面已经有了这个下载任务就直接返回。
if self.oprationCache.objectForKey(model.icon) != nil{
return
}
//2.异步下载图片
//注意:只要是网络上的图片就必须异步加载
let operation = NSBlockOperation {
let data = NSData(contentsOfURL: NSURL(string: model.icon)!)
//避免网络不好下载不了图片,在强制解包导致程序崩溃
if data == nil{
print("网络错误")
return
}
let image = UIImage(data: data!)//强制解包
//3.将数据保存到程序的缓存中
//将model的icon作为Key,image作为值存到imageCache中
self.imageCach.setObject(image!, forKey: model.icon)
//4.将数据保存到本地!!!
//print(NSHomeDirectory())
//将二进制数据写入指定的文件中
//参数1:文件路径
//参数2:是否进行原子操作(是否进行异步进行写操作)
//获取icon的最后一个部分作为文件名
let iconStr = model.icon as NSString
let lastStr = iconStr.lastPathComponent
data?.writeToFile(imageCache_Path + "/" + lastStr, atomically: false)
//5.回到主线程
NSOperationQueue.mainQueue().addOperationWithBlock({
//刷新cell
self.tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
})
}
self.queue.addOperation(operation)
//6.将任务保存到缓存中
self.oprationCache.setObject(operation, forKey: model.icon)
}
}
封装版
封装版用的数据模型DataModel以及cell和未封装版是一样的,这里不重复放出,封装版也就是写了系统自带的UIImageView类的扩展,给它增加一个方法来设置图片(仿照OC第三方库SDWebImage,下文讲解),这个方法的作用是:在需要设置图片的时候,先判断设置所需要的图片是否在本地有缓存,如果有就直接使用,如果没有就异步下载图片并且缓存图片,在下载成功之前用默认图片顶替
- ViewController
import UIKit
class ViewController: UITableViewController {
//MARK: - 属性
//1.数据源数组
lazy var dataArray:[DataModel] = {
return self.getData()
}()
//MARK: - 生命周期
override func viewDidLoad() {
super.viewDidLoad()
//注册cell
self.tableView.registerNib(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "cell")
//设置行高
self.tableView.rowHeight = 120
}
}
extension ViewController{
func getData() -> [DataModel]{
var tempArray = [DataModel]()
//1.获取plist路径
let path = NSBundle.mainBundle().pathForResource("model.plist", ofType: nil)
//2.拿到plist文件中的数组
let plistArray = NSArray(contentsOfFile: path!)
//3.遍历数组拿到所有字典
for item in plistArray!{
let dict = item as! NSDictionary
//4.根据字典创建对应的字典模型
let model = DataModel(dict: dict)
//5.将模型保存到数组中
tempArray.append(model)
}
return tempArray
}
}
//MARK: - 协议方法
extension ViewController{
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//1.创建cell
let cell = tableView.dequeueReusableCellWithIdentifier("cell",forIndexPath: indexPath) as! TableViewCell
//2.刷新数据
let model = self.dataArray[indexPath.row]
cell.nameLabel.text = model.name
cell.downloadLabel.text = model.download
cell.iconImageView?.ZGJ_setImage(model.icon, placeholderImageName: "user_default.png")
//3.返回cell
return cell
}
}
- UIImageView类的扩展
import UIKit
///图片缓存目录
let imageCache_Path = NSHomeDirectory() + "/Library/Caches/imageCache"
extension UIImageView{
func ZGJ_setImage(urlStr:String,placeholderImageName:String){
//判断当前这个图片是否有本地缓存
let fileName = (urlStr as NSString).lastPathComponent
let getData = NSData(contentsOfFile: imageCache_Path + "/" + fileName)
if getData != nil{
self.image = UIImage(data: getData!)
return
}else{
self.image = UIImage(named: placeholderImageName)
}
//创建缓存图片的文件夹
do{
try NSFileManager.defaultManager().createDirectoryAtPath(imageCache_Path, withIntermediateDirectories: true, attributes: nil)
}catch{}
//1.异步下载图片
dispatch_async(dispatch_get_global_queue(0, 0)) {
let data = NSData(contentsOfURL: NSURL(string: urlStr)!)
if data == nil{
print("网络错误")
return
}
let image = UIImage(data: data!)
//2.将图片保存到本地
data?.writeToFile(imageCache_Path + "/" + fileName, atomically: true)
//3.回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), {
self.image = image
})
}
}
}
使用第三方库下载图片
下载图片经常使用的第三方库有OC版本的SDWebImage和Swift版本的Kingfisher,在这里只介绍利用第三方库下载图片的相关方法,如何使用第三方库请跳转http://www.jianshu.com/p/734f7b1280f3
使用OC第三方库SDWebImage异步下载图片
GET
使用SDWebImage下载图片的时候会自动缓存到本地,不用自己写
例子中的DataModel及cell与上面的一样
import UIKit
//在swift中使用OC第三方库
//1.将第三方库文件拖到工程中
//2.创建桥接文件
//a.通过新建文件创建一个.h文件(命名规则:xxx-Briding-Header)
//b.在桥接文件中将需要使用的头文件通过“#import”包含进去
//c.设置工程文件
class ViewController: UITableViewController {
//MARK: - 属性
//1.数据源数组
lazy var dataArray:[DataModel] = {
return self.getData()
}()
//MARK: - 生命周期
override func viewDidLoad() {
super.viewDidLoad()
//注册cell
self.tableView.registerNib(UINib(nibName: "TableViewCell", bundle: nil), forCellReuseIdentifier: "cell")
//设置行高
self.tableView.rowHeight = 120
}
}
extension ViewController{
func getData() -> [DataModel]{
var tempArray = [DataModel]()
//1.获取plist路径
let path = NSBundle.mainBundle().pathForResource("model.plist", ofType: nil)
//2.拿到plist文件中的数组
let plistArray = NSArray(contentsOfFile: path!)
//3.遍历数组拿到所有字典
for item in plistArray!{
let dict = item as! NSDictionary
//4.根据字典创建对应的字典模型
let model = DataModel(dict: dict)
//5.将模型保存到数组中
tempArray.append(model)
}
return tempArray
}
}
//MARK: - 协议方法
extension ViewController{
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//1.创建cell
let cell = tableView.dequeueReusableCellWithIdentifier("cell",forIndexPath: indexPath) as! TableViewCell
//2.刷新数据
let model = self.dataArray[indexPath.row]
cell.nameLabel.text = model.name
cell.downloadLabel.text = model.download
//通过SDWebImage做图片的异步下载和缓存
//参数1:图片网络路径对应的url
//参数2:占位图
//老版
//cell.iconImageView.setImageWithURL(NSURL(string: model.icon), placeholderImage: UIImage(named: "user_default.png"))
//新版
cell.iconImageView.sd_setImageWithURL(NSURL(string: model.icon), placeholderImage: UIImage(named: "user_default.png"))
//print(NSHomeDirectory())
//3.返回cell
return cell
}
}
使用Swift的第三方库Kingfisher异步下载图片
GET
使用Kingfisher下载图片的时候会自动缓存到本地,不用自己写
由于在使用Kingfisher下载图片的时候还使用了其他的第三方库,所以这里不单独介绍,请跳转链接:http://www.jianshu.com/p/4d831be7da17