ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ios - Swift] NSCache Image 사용하기
    ios 2021. 2. 9. 17:57

     

     

    안녕하세요.

     

    이번에 소개할 내용은 NSCache입니다.

     

    앱에서 사용할 이미지를 매번 서버에서 불러오게 된다면 된다면 자원 낭비이기 때문에

     

    이번 글에서는 이를 해결하기 위해 캐시에 대해 정리하려고 합니다.

     

     

    캐시란 데이터나 값을 미리 복사해 놓는 임시 장소라고 정의되어있습니다.

     

    이를 이용해서 동일한 작업을 진행할 때 작업 시간이 오래 걸리는 데이터를  미리 저장해 두었다가 사용하는 것을 의미합니다.

     

     

    우리는 NSCache를 사용한 메모리 캐시FileManager를 사용한 디스크 캐시의 사용 방법 및 성능 차이를 비교해 보도록 하겠습니다.

     

     

     

     

    1. 메인 스토리 보드 작성

     

    메인 스토리 보드의 디자인은 버튼과 이미지 뷰를 이용해 제작하였고 각 버튼의 기능은 다음과 같습니다.

     

    FIle Delete : FileManager를 사용해 저장된 이미지를 삭제

    Clear : 이미지 뷰의 이미지를 nil 처리

    FileManager Load : 저장되어있는 Data를 이미지 뷰로 불러옴

    NSCache Load : 저장되어있는 Cache를 이미지 뷰로 불러옴

     

     

     

    2. 소스 작성

     

    import UIKit
    
    class ViewController: UIViewController {
        @IBOutlet weak var imageView: UIImageView!
        
        private let ImageCache = NSCache<NSString, UIImage>()
        private let UserFileManager = FileManager.default
        
        let imageUrlString = "https://wallpapercave.com/wp/wp5437792.jpg"
    
        override func viewDidLoad() {
        
        
        
        ...

    이미지 주소와 이미지를 관리할 Cache, FileManger를 선언하기만 하면 됩니다.

     

    NSCache : 메모리 캐싱 방식을 사용하고 키와 값으로 데이터를 관리하는데 리소스가 부족할 때는 데이터가 지워집니다.

    FileManager : 디스크 캐싱 방식을 사용하며 메모리 캐시보다는 상대적으로 느리지만 데이터는 지워지지 않습니다.

     

    메모리 캐시 : 처리속도가 빠르나 저장공간이 작으며 앱 재실 행시 데이터는 사라짐

    디스크 캐시 : 처리속도는 상대적으로 느리나 저장공간이 크고 데이터는 보존

     

    메모리 캐시의 경우 리소스를 관리하기 위해 캐시가 보유하는 개채 수, 비용 등을 관리해 캐시를 줄일 수 있습니다.

     

     

    public func measureTime(_ closure: () -> ()) -> TimeInterval {
        let startDate = Date()
        closure()
        return Date().timeIntervalSince(startDate)
    }

    이미지 로드 함수의 동작 시간을 측정하기 위한 함수입니다.

     

     

    @IBAction func FileManagerDelete(_ sender: UIButton) {
        guard let imageUrl = URL(string: imageUrlString) else { return }
        guard let cachesDir = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first else { return }
            
        var filePath = URL(fileURLWithPath: cachesDir)
        filePath.appendPathComponent(imageUrl.lastPathComponent)
        
        try? UserFileManager.removeItem(atPath: filePath.path)
    }

    디스크에 저장된 이미지 데이터를 제거할 함수입니다.

     

     

    @IBAction func ImageViewClear(_ sender: UIButton) {
        imageView.image = nil
    }

    이미지 뷰의 이미지를 제거합니다.

     

    @IBAction func ImageViewDiskLoad(_ sender: UIButton) {
        let interval = measureTime {
            guard let imageUrl = URL(string: imageUrlString) else { return }
            guard let cachesDir = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first else { return }
                
            var filePath = URL(fileURLWithPath: cachesDir)
            filePath.appendPathComponent(imageUrl.lastPathComponent)
            
            var imageData: Data?
            
            if UserFileManager.fileExists(atPath: filePath.path) {
                imageData = try? Data(contentsOf: filePath)
            } else {
                imageData = try? Data(contentsOf: imageUrl)
                UserFileManager.createFile(atPath: filePath.path, contents: image!.jpegData(compressionQuality: 0.4), attributes: nil)
            }
            
            imageView.image = UIImage(data: imageData!)
        }
        print("Disk Memory : \(interval)")
    }

    이미지를 디스크에서 불러오며 처리방법은 다음과 같습니다.

    1. 이미지 데이터 저장 경로에 데이터가 있는지 확인

    2. 데이터가 존재하면 데이터를 불러온 후 이미지 뷰에 표시 / 데이터가 존재하지 않으면 이미지 URL을 통해 데이터를 생성 및 저장 후 이미지 뷰에 표시

     

     

    @IBAction func ImageViewCacheLoad(_ sender: UIButton) {
        let interval = measureTime {
            guard let imageUrl = URL(string: imageUrlString) else { return }           
            guard let cachesDir = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first else { return }
                
            var filePath = URL(fileURLWithPath: cachesDir)
            filePath.appendPathComponent(imageUrl.lastPathComponent)
             
            var imageData: Data?
             
            if UserFileManager.fileExists(atPath: filePath.path) {
                if let cacheImage = ImageCache.object(forKey: filePath.lastPathComponent as NSString) {
                    imageView.image = cacheImage
                    return
                }
                imageData = try? Data(contentsOf: filePath)
             
            } else {
                imageData = try? Data(contentsOf: imageUrl)
            }
                
            let image = UIImage(data: imageData!)
            imageView.image = image
            ImageCache.setObject(image!, forKey: filePath.lastPathComponent as NSString)
            UserFileManager.createFile(atPath: filePath.path, contents: image!.jpegData(compressionQuality: 0.4), attributes: nil)
        }
        print("Cache Memory : \(interval)")
    }
    

    이미지를 메모리에서 불러오며 처리방법은 다음과 같습니다.

    1. 이미지 데이터 저장 경로에 데이터가 있는지 확인하며 있을 경우 이미지 캐시에 저장 유무에 따라 데이터를 불러온 후 리턴 / 없을 경우 파일 경로에서 불러온다.

    2. 이미지가 없을 경우 URL 통해 데이터를 생성한다.

    3. 이미지 뷰에 이미지 표시 및 캐시, 디스크 저장

     

     

     

    이제 앱을 구동 후 성능을 비교해 보도록 하겠습니다.

     

    앱 실행 후 NSCache Load를 클릭하면 이미지 데이터가 없기때문에 네트워크를 통해 데이터를 불러오며 이미지 뷰에 출력까지 걸리는 시간은 다음과 같습니다.

     

    클리어 버튼을 선택 후 다시 한번 NSCache Load를 클릭하면 캐시 데이터가 존재하기때문에 출력까지 걸리는 시간은 다음과 같습니다.

     

    이제 FileManager를 이용해 데이터 출력의 경과 시간은 다음과 같습니다.

     

     

     

    댓글

Designed by Tistory.