Image Caching

주방·2023년 5월 10일
0

MovieRank

목록 보기
7/8
post-thumbnail

이미지 처리

배경

  • pagenation 처리를 하는데 있어 이미지가 곧바로 표시되지 않는 이슈가 발생함.
  • 왜 이미지가 곧바로 표시되지 않는 것일까?
  • 현재 MainViewCell 클래스의 setImage 메서드에서 viewModel.downloadImage 메서드를 호출하여 이미지를 다운로드하고 있음.
  • 각 셀마다 API에서 이미지를 다운로드해 표시하고 있기 때문에 스크롤이 될 때마다 반복 요청하고 있었음.
  • 이러한 문제를 해결하기 위한 방법을 탐색함.

이미지 처리 방법

  1. 이미지 캐싱
    • 캐싱의 의미
      • 저장하는 것. 오래 걸리는 작업을 저장해 두었다가 동일한 작업을 수행할 때 저장된 결과를 가져와 사용하는 것을 말함.
      • 즉, 한번 다운로드된 이미지를 메모리 캐시, 디스크 캐시에 저장해두었다가 같은 이미지를 불러올 일이 생기면 내부적으로 해당 이미지가 존재하는지 확인하고 있다면 이미지를 반환해주는 방식으로 동작됨.
    • 이미지 캐싱
      • ios에서는 이미지 캐싱 처리할 대 NSCache(메모리), FileManager(디스크)라는 2개의 클래스를 이용함.
      • 메모리 캐싱?
        • NSCache를 이용해서 구현할 수 있는 기능
        • 이미지를 앱의 메모리에 저장하고, 필요할 경우 빠르게 액서스 할 수 있음.
        • 그러나 기기를 끄면 캐싱된 내용이 사라지며, 저장공간이 작음.
      • 디스크 캐싱?
        • 앱을 삭제할 때 캐싱된 데이터도 삭제(UserDefaults)하게 만들수도 있고, 그렇지 않고 계속 남아 있기 만들수도 있음(FileManager )
        • 캐싱할 데이터를 기기 내부에 아카이빙하는 방벙브로 기기를 껐다 켜도 저장됨
        • 저장공간은 상대적으로 크지만, 파일 입출력으로 인해 처리속도가 메모리 캐싱방법보다는 느림.
    • 이미지 캐싱 과정
      • 필요 이미지 발생
      • 메모리 캐시 또는 디스크 캐시에서 해당 이미지를 검색
      • 없는 경우, URLString으로 이미지를 네트워크 다운로드
      • 메모리 캐시 또는 디스크 캐시에 해당 이미지를 저장
      • 저장된 공간에서 이미지 불러옴
  2. Kingfisher
    • url 방식으로 이미지를 받아오는 것을 비동기적으로 처리하고, 받아온 이미지를 캐싱하여 사용할 수 있게 해주는 라이브러리이다.
    • 메모리 캐시 + 디스크 캐시

이미지 캐싱 비교

  • 캐싱 안한경우NSCacheFileManagerKingfisher
    notimagecachingmemorycachingdiskcachingkingfisher
  • 비교를 위해 Unsplsh의 인기있는 용량이 큰 사진 30종을 불러올 수 있는 API를 사용하였음.

  • 구현

    • 캐싱 안함

      • 캐싱을 하지 않았을 경우, 반복적인 호출로 인해 이미지가 밀리거나 빈화면을 보여주는 등의 불편함을 보여주었음.
    • NSCache

      • 데이터를 key-value 로 저장하는 컬렉션으로 캐싱된 데이터가 너무 많은 메모리를 사용하면 시스템에서 자동으로 캐시된 메모리를 삭제해줌

      • 자원이 부족할 때 삭제 대상

      • 생성 비용이 많이 드는 일시적인 데이터 객체를 저장

      • 값을 다시 계산할 필요가 없으므로 이러한 객체를 재사용하는 것은 성능상의 이점을 얻을 수 있음.

      • 캐싱을 하지 않은 경우와 확연한 차이를 보여주었음. 캐싱이 끝난 후부터는 상단으로 뷰를 올려도 자연스럽게 이미지를 표시하였음.

      • // NSCache를 사용해 이미지를 메모리에 캐시하였음.
        // 이미지가 캐시에 있으면 반환하고, 아니면 다운로드를 진행함.
        private let imageCache = NSCache<NSString, UIImage>()
        
        func downloadImage(posterPath: String, completion: @escaping(Result<UIImage, Error>) -> Void) {
        
            if let cachedImage = imageCache.object(forKey: posterPath as NSString) {
                completion(.success(cachedImage))
                return
            }
        //  (중략)
        }
    • FileManager

      • 캐싱된 데이터가 자체 디렉토리를 만들어서 아카이빙 됨.

      • 파일시스템은 앱의 샌드박스라고 불리는 독립된 공간에 위치함. 샌드박스는 앱의 보안을 위해 다른 앱이나 시스템에 접근할 수 없는 영역임.

      • swift에서는 FileManager라는 클래스를 통해 파일시스템에 접근할 수 있음.

      • 캐싱을 하지 않은 경우와 확연한 차이를 보여주었음. 캐싱이 끝난 후부터는 상단으로 뷰를 올려도 자연스럽게 이미지를 표시하였음.

      • // FileManager 사용해 이미지를 디스크에 캐시하였음.
        // 이미지가 캐시에 있으면 반환하고, 아니면 다운로드를 진행함.
        func downloadImage(posterPath: String, completion: @escaping(Result<UIImage, Error>) -> Void) {
            let fileManager = FileManager.default
            let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0]
            let fileName = posterPath.replacingOccurrences(of: "/", with: "_")
            let fileURL = cacheDirectory.appendingPathComponent(fileName)
            
            if let image = UIImage(contentsOfFile: fileURL.path) {
                completion(.success(image))
                return
            }
    • Kingfisher

      • 이미지 로드, 캐시 기능, 이미지 가져오는 동안 애니메이션 기능 제공 등 다양한 기능을 제공함. 라이브러리 자체 내에서 메모리, 디스크에 캐시하여 처리하였음.

      • 4가지 중에 가장 구현이 매끄러웠음을 확인할 수 있었으며, 코드 구현이 가장 간단했음.

      • func setImage(urlString: String) {
                if let url = URL(string: urlString) {
                    imageView.kf.setImage(with: url)
                }
            }

정리

  1. 이미지 크기가 크지 않거나, 갯수가 많지 않은 경우 이미지 캐싱의 필요성을 느끼지 못했음.
  2. 그러나 갯수가 많아지면서 반복적인 호출은 정보 표시, 디바이스 등에 부담을 준다는 것을 느낌.(무척 버벅임)
  3. 이미지 캐싱을 적용했을 때, 조작시 사용자가 자연스러운 조작이 가능하도록 이미지 로딩 시간이 줄어든 상태로 정보를 표시해주었음.(메모리, 디스크, kingfisher)
  4. 코드 구현에 있어 Kingfishser가 메모리, 디스크에 비해 수월함.
  5. 결론: 메모리, 디스크 , Kingfisher 모두 이미지 로딩시간을 줄여주었으나, Kingfisher는 메모리, 디스크 2가지를 적절하게 체크하기 때문에 어느 한쪽으로 치우친 부담을 주지 않을 수 있음. MovieRankApp Pagenation 시 발생하는 문제에 적용하고 해결해야겠음.

참조링크

  1. https://velog.io/@cooo002/ios%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%BA%90%EC%8B%B1%EC%B2%98%EB%A6%AC-%EA%B0%9C%EB%85%90
  2. https://ios-development.tistory.com/659
  3. https://kirkim.github.io/swift/2022/08/08/nscache.html
  4. https://kirkim.github.io/swift/2022/08/13/filemanager.html
  5. https://velog.io/@mmim/iOS-swift-Cache%EC%99%80-NSCache-%EA%B0%9C%EB%85%90
  6. https://yoonah-dev.oopy.io/c16f8f25-5ded-4ddb-a9f5-c0d15bd3490f
  7. https://ios-development.tistory.com/793

0개의 댓글