The implemented
- Network request to get pictures
- Memory cache pictures
- Disk cache picture
- Get disk cache data size
- Delete the cache of the specified picture
- Delete all picture caches
- UIImageView Corresponding classification ( Support the change of occupation bitmap and occupation bitmap display mode )
For other classes to set up network pictures, please refer to UIImageView classification
extension <# Class name #>: RBWebImageProtocol {
func <# Method name #>(url: URL, <# The other parameters #>) {
// 1. Get the picture from the cache and load
if let cacheImage = RBWebImageCach.getCacheImage(urlStr: url.absoluteString) {
// Picture found in cache , Update picture
<#code#>
return
}
// 2. When there is no picture in the cache, request picture data through the network
getData(url: url!) {[weak self] (data) in
if data == nil {
// The data requested by the network is empty
<#code#>
}else {
if let ima = UIImage(data: data!) {
// Network request to picture
<#code#>
// Cache pictures data
RBWebImageCach.saveImageData(data: data!, urlStr: (url!.absoluteString))
}else {
// Failed to convert the data requested by the network to pictures
<#code#>
}
}
}
}
}
Copy code
technological process
- adopt url Set pictures
- adopt url Get pictures from cache ( Now look in memory , Not found in memory, and then go to disk to find )
- After the cache finds the picture, it will be set directly
- If it is not found in the cache, it requests the picture through the network
- After requesting data, go to the main thread to set the picture
Main documents
RBWebImageProtocol
agreement , Through the extension of the protocol, the function of obtaining picture data on the network is realized
import Foundation
import UIKit
protocol RBWebImageProtocol {
/// adopt url obtain data
/// - Parameters:
/// - url: url
/// - completion: Callback after completion
func getData(url: URL, completion: ((Data?) -> Void)?)
}
extension RBWebImageProtocol {
/// adopt url obtain data
/// - Parameters:
/// - url: url
/// - completion: Callback after completion
func getData(url: URL, completion: ((Data?) -> Void)? = nil) {
// Create parallel queues to execute asynchronously
DispatchQueue(label: "com.RBWebImage.concurrentQueue",attributes:.concurrent).async {
do {
let data: Data = try Data(contentsOf: url)
if data.count > 0 {
completion?(data)
}else {
completion?(nil)
}
} catch _ {
completion?(nil)
}
}
}
}
Copy code
RBWebImageCach
Cache management class , All functions related to caching
- RBWebImageMemoryManager Memory cache management class
- RBWebImageDiskManager Disk cache management class
import Foundation
import UIKit
fileprivate func showLog(_ msg: String) {
if isShowRBWebImageLog {
print(msg)
}
}
class RBWebImageCach {
/// Get images from the cache
/// - Parameter urlStr: picture url
/// - Returns: Pictures in cache
class func getCacheImage(urlStr: String) -> UIImage? {
let key = getKeyString(urlStr: urlStr)
// Get pictures from memory
showLog(" Will go to memory to get the cache :\(urlStr)")
if let cacheImage = RBWebImageMemoryManager.shared.getImage(key: key) {
showLog(" Picture found in memory :\(urlStr)")
return cacheImage
}
showLog(" Not found in memory , Will go to disk to get cache :\(urlStr)")
// When there is no memory , Get picture data from disk
if let data = RBWebImageDiskManager.shared.getData(key: key) {
if let cacheImage = UIImage(data: data) {
showLog(" Picture found on disk :\(urlStr)")
return cacheImage
}
}
return nil
}
/// Save picture data
/// - Parameters:
/// - data: Picture data
/// - urlStr: picture url
class func saveImageData(data: Data, urlStr: String) {
let key = getKeyString(urlStr: urlStr)
if let image = UIImage(data: data) {
// Cache into memory
showLog(" Store in memory :\(urlStr)")
RBWebImageMemoryManager.shared.saveImage(image: image, key: key)
// Cache to disk
showLog(" Storage to disk :\(urlStr)")
RBWebImageDiskManager.shared.saveImage(data: data, key: key)
}else {
showLog(" Invalid data :\(urlStr)")
}
}
/// Delete all cached data
class func deleteAllCacheData() {
// Delete all cached data in memory
RBWebImageMemoryManager.shared.deleteAllImage()
// Delete all cached data on disk
RBWebImageDiskManager.shared.deleteAllCacheData()
}
class func deleteCacheData(urlStr: String) {
let key = getKeyString(urlStr: urlStr)
// Delete cached data in memory
RBWebImageMemoryManager.shared.deleteImage(key: key)
// Delete cached data on disk
RBWebImageDiskManager.shared.deleteCacheData(key: key)
}
/// Get the size of cached picture data
/// - Returns: Size of picture data
class func getCacheSize() -> Double {
return RBWebImageDiskManager.shared.getCacheSize()
}
/// according to url String to get the cache key
/// - Parameter urlStr: url character string
/// - Returns: key
private class func getKeyString(urlStr: String) -> String {
var key = urlStr
for s in ":/\\." {
key = key.replacingOccurrences(of: String(s), with: "_")
}
return key
}
}
/// Memory cache management class
class RBWebImageMemoryManager {
static let shared = RBWebImageMemoryManager()
private init() {}
private let cache = NSCache<NSString, UIImage>()
private var keys = Array<NSString>()
/// Save picture to memory
/// - Parameters:
/// - image: picture
/// - key: key
func saveImage(image: UIImage, key: String) {
let nKey = key as NSString
if !keys.contains(nKey) {
keys.append(nKey)
}
cache.setObject(image, forKey: nKey)
}
/// adopt key Get pictures in memory
/// - Parameter key: key
/// - Returns: Pictures in memory
func getImage(key: String) -> UIImage? {
return cache.object(forKey: key as NSString)
}
/// Delete all pictures in memory
func deleteAllImage() {
cache.removeAllObjects()
keys.removeAll()
}
/// Delete key The corresponding picture
/// - Parameter key: key
func deleteImage(key: String) {
let nKey = key as NSString
cache.removeObject(forKey: nKey)
}
}
/// Disk cache management class
class RBWebImageDiskManager {
static let shared = RBWebImageDiskManager()
private init() {}
private let cachePath = "\(NSHomeDirectory())/Library/Caches/BGWebImageCache"// Cache path
/// Save data to disk
/// - Parameters:
/// - data: data
/// - key: key
func saveImage(data: Data, key: String) {
let path: String = getFullCachePath(key: key)
if FileManager.default.createFile(atPath: path, contents: data, attributes: nil) {
showLog(" Saved successfully ")
}else {
showLog(" Save failed ")
}
}
/// adopt key Get picture data on disk
/// - Parameter key: key
/// - Returns: Picture data on disk
func getData(key: String) -> Data? {
var data:Data?
let path: String = getFullCachePath(key: key)
if FileManager.default.fileExists(atPath: path) {
data = FileManager.default.contents(atPath: path)
}
return data
}
/// Delete all picture data on disk
func deleteAllCacheData() {
let fileManager: FileManager = FileManager.default
if fileManager.fileExists(atPath: cachePath) {
do {
try fileManager.removeItem(atPath: cachePath)
} catch {
showLog(" Delete disk cache exception ")
}
}
}
/// Delete key Corresponding picture data
/// - Parameter key: key
func deleteCacheData(key: String) {
let path = getFullCachePath(key: key)
let fileManager: FileManager = FileManager.default
if fileManager.fileExists(atPath: path) {
do {
try fileManager.removeItem(atPath: path)
} catch {
showLog(" Delete disk cache exception ")
}
}
}
/// Get the total size of pictures on disk
/// - Returns: size
func getCacheSize() -> Double {
let manage = FileManager.default
if !manage.fileExists(atPath: cachePath) {
return 0
}
let childFilePath = manage.subpaths(atPath: cachePath)
var size:Double = 0
for path in childFilePath! {
let fileAbsoluePath = cachePath+"/"+path
size += getFileSize(filePath: fileAbsoluePath)
}
return size
}
/// adopt key Get the full cache path
/// - Parameter key: key
/// - Returns: Full cache path
private func getFullCachePath(key: String) -> String {
let path = "\(cachePath)/\(key)"
let fileManager: FileManager = FileManager.default
if !(fileManager.fileExists(atPath: cachePath)) {
do {
try fileManager.createDirectory(atPath: cachePath, withIntermediateDirectories: true, attributes: nil)
return path
}catch {
showLog(" Cache full path setting failed ")
return ""
}
}
return path
}
/// Get file size
/// - Parameter filePath: File path
/// - Returns: file size
private func getFileSize(filePath: String) -> Double {
let manager = FileManager.default
var fileSize:Double = 0
do {
let attr = try manager.attributesOfItem(atPath: filePath)
// fileSize = Double(attr[FileAttributeKey.size] as! UInt64)
let dict = attr as NSDictionary
fileSize = Double(dict.fileSize())
} catch {
showLog("\(error)")
}
return fileSize
}
}
Copy code
UIImageView+RBWebImage
UIImageView An extension of , Realization UIimageView Set the function of network picture
import UIKit
let isShowRBWebImageLog = true
extension UIImageView: RBWebImageProtocol {
/// Set up network pictures
/// - Parameters:
/// - url: url
/// - defaultImage: Occupation map
/// - isKeepOriginal: When there were pictures , Whether to keep the original picture (true: Do not replace bitmap ,false: Replace the bitmap every time )
/// - completion: Callback after completion
func rbSetImage(url: URL?, defaultImage: UIImage?, isKeepOriginal: Bool = false, completion: ((UIImage?) -> Void)? = nil) {
showLog(" Start setting up network pictures :\(url?.absoluteString ?? "")")
if !isKeepOriginal {
self.image = nil
}
let originImage = self.image
if originImage == nil && defaultImage != nil {
self.image = defaultImage!
}
if url == nil {
completion?(nil)
showLog(" Setup failed :url empty ")
return
}
// Get the picture from the cache and load
if let cacheImage = RBWebImageCach.getCacheImage(urlStr: url!.absoluteString) {
// Update the picture in the main thread
DispatchQueue.main.async {[weak self] in
self?.image = cacheImage
}
self.showLog(" Set up the success :\(url!.absoluteString)")
return
}
showLog(" Failed to get picture from cache :\(url!.absoluteString)")
// When there is no picture in the cache, request picture data through the network
showLog(" Start requesting picture data through the network :\(url!.absoluteString)")
getData(url: url!) {[weak self] (data) in
if data == nil {
completion?(nil)
self?.showLog(" Setup failed : The data requested by the network is empty -\(url!.absoluteString)")
}else {
if let ima = UIImage(data: data!) {
// Update the picture in the main thread
DispatchQueue.main.async {[weak self] in
self?.image = ima
}
// Cache pictures data
RBWebImageCach.saveImageData(data: data!, urlStr: (url!.absoluteString))
self?.showLog(" Set up the success :\(url!.absoluteString)")
completion?(ima)
}else {
self?.showLog(" Setup failed : Failed to convert the data requested by the network to pictures -\(url!.absoluteString)")
completion?(nil)
}
}
}
}
/// Set up network pictures
/// - Parameters:
/// - urlStr: url character string
/// - defaultImageName: Bitmap name
func rbSetImage(urlStr: String, defaultImageName: String?) {
var defauleImage: UIImage? = nil
if defaultImageName != nil {
defauleImage = UIImage(named: defaultImageName!)
}
var url: URL? = nil
if let us = urlStr.urlString() {
url = URL(string: us)
}
rbSetImage(url: url, defaultImage: defauleImage, isKeepOriginal: false, completion: nil)
}
/// Print log
/// - Parameter msg: msg Log information
private func showLog(_ msg: String) {
if isShowRBWebImageLog {
print(msg)
}
}
}
extension String {
/// format url
/// - Returns: format url character string
func urlString() -> String? {
if self.count == 0 {
return nil
}
let urlStr = CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, self as CFString, "!$&'()*+,-./:;[email protected]_~%#[]" as CFString) as String?
if urlStr == nil || urlStr?.count == 0 {
return nil
}
return urlStr
}
}
Copy code