iOS - 이미지캐싱

이한솔·2023년 12월 7일
0

iOS 앱개발 🍏

목록 보기
39/45

캐싱

캐싱은 재사용될 수 있는 자원을 특정 영역에 저장해놓는 것을 의미한다. 캐싱된 데이터가 있다면 추가적인 자원을 소모하지 않고 캐싱 데이터를 가져다 쓸 수 있기 때문에 자원을 절약할 수 있고 애플리케이션의 처리 속도가 향상된다.



이미지 캐싱 방법

메모리 캐싱

메모리 캐시는 휘발성 메모리(RAM)에 데이터를 저장하여 빠른 접근이 가능하지만, 앱이 종료되면 메모리에서 캐시 데이터도 같이 삭제된다. NSCache를 사용하며, 이는 key:value로 이루어진 제네릭 클래스다.

import UIKit

// MARK: - ImageCache
class ImageCache {
    static let shared = NSCache<NSString, UIImage>()
}


// MARK: - ViewController
class ViewController: UIViewController {
    
    let imageView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let imageURL = URL(string: "https://example.com/image.jpg")!
        loadImage(from: imageURL)
    }

    func loadImage(from url: URL) {
        let cacheKey = NSString(string: url.absoluteString)
        
        // 메모리 캐시에서 이미지 로드
        if let cachedImage = ImageCache.shared.object(forKey: cacheKey) {
            imageView.image = cachedImage
            return
        }
        
        // 메모리 캐시에 이미지가 없으면 네트워크에서 로드
        DispatchQueue.global().async {
            if let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self.imageView.image = image
                    ImageCache.shared.setObject(image, forKey: cacheKey)
                }
            }
        }
    }
}

UIImageView를 extension하는 방법으로도 사용 가능하다.

import UIKit


// MARK: - UIImageView
extension UIImageView {
    
    func setImageUrl(_ urlString: String) {
        DispatchQueue.global(qos: .background).async {
            let cacheKey = NSString(string: urlString) // 캐시 키 생성
            
            // 메모리 캐시에서 이미지 로드
            if let cachedImage = ImageCache.shared.object(forKey: cacheKey) {
                DispatchQueue.main.async {
                    self.image = cachedImage
                }
                return
            }
            
            // 유효한 URL인지 확인
            guard let url = URL(string: urlString) else { return }
            
            // URLSession을 사용하여 이미지 다운로드
            URLSession.shared.dataTask(with: url) { (data, response, error) in
                if error != nil {
                    DispatchQueue.main.async {
                        self.image = nil
                    }
                    return
                }
                
                DispatchQueue.main.async {
                    if let data = data, let image = UIImage(data: data) {
                        // 다운로드한 이미지를 캐시에 저장
                        ImageCache.shared.setObject(image, forKey: cacheKey)
                        self.image = image
                    }
                }
            }.resume()
        }
    }
}


디스크 캐싱

디스크 캐시는 FileManager를 사용하여 데이터를 파일 시스템에 저장하여 영구적으로 보존 가능하다.

import UIKit

// MARK: - DiskCache
class DiskCache {
    static let shared = DiskCache()

    private init() {}
    
    let fileManager = FileManager.default

    func cacheDirectory() -> URL {
        return fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!
    }

    func saveData(_ data: Data, forKey key: String) {
        let fileURL = cacheDirectory().appendingPathComponent(key)
        do {
            try data.write(to: fileURL)
        } catch {
            print("Error saving data to disk: \(error)")
        }
    }

    func loadData(forKey key: String) -> Data? {
        let fileURL = cacheDirectory().appendingPathComponent(key)
        return try? Data(contentsOf: fileURL)
    }
}


// MARK: - ViewController
class ViewController: UIViewController {

    let imageView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let imageURL = URL(string: "https://example.com/image.jpg")!
        loadImage(from: imageURL)
    }

    func loadImage(from url: URL) {
        let cacheKey = url.lastPathComponent
        
        // 디스크 캐시에서 이미지 로드
        if let cachedData = DiskCache.shared.loadData(forKey: cacheKey), let image = UIImage(data: cachedData) {
            imageView.image = image
            return
        }
        
        // 디스크 캐시에 이미지가 없으면 네트워크에서 로드
        DispatchQueue.global().async {
            if let data = try? Data(contentsOf: url), let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self.imageView.image = image
                    DiskCache.shared.saveData(data, forKey: cacheKey)
                }
            }
        }
    }
}

0개의 댓글