관리 메뉴

사과하는 제라스

[Swift 기능] Image Caching 처리 in UIKit 본문

제라스의 iOS 공부/Swift 기능

[Swift 기능] Image Caching 처리 in UIKit

Xerath(제라스) 2024. 4. 29. 03:34

목차

    728x90
    반응형

    서론

    안녕하세요! 개발자 제라스입니다! 👋🏻🤖👋🏻

    너무 오랜만에 돌아왔습니다 ㅠㅠ

    요새 프로젝트들을 하고 개인 공부를 하다보니 포스팅이 많이 늦어졌네요...

     

    오늘은 Image Caching(이미지 캐싱)을 다뤄보고자 합니다!

    사실 지난주에 UIKit 공부를 하다가 어떤 기능을 구현하는데 API로부터 수많은 양의 Image를 받아오다보니 로드에 시간이 오래 걸리거나 네트워킹이 뻑나는 현상을 마주하게 되었어요!

     

    딱 보자마자 '으에ㅔ에ㅔㅔ?! 이거 네부캠 때 배웠던 이미지 캐싱 적용해야겠다!?!' 라는 생각이 들더라구요!

    근데 당시에 배워서 구현도 해봤지만 제라스의 망각곡선의 효과는 상당했습니다 ㅋㅋㅋㅋㅋㅋㅋ

    4개월동안 구현을 안하니 잊어버렸습니다 😭😭

     

    그래서 이참에 한번 정리하면서 머리 깊이 넣어두려구요!!

    덕분에 오랜만의 기술 포스팅이라 설렙니다 흐하하하하

     

    그럼 한번 시작해보겠습니다.

    이미지 캐싱이 뭔데?

    일단 '캐시(Cache)'가 뭔지부터 보면 자주 사용하는 데이터나 값을 미리 복사해 놓는 임시 장소입니다!

    가장 쉽게 볼 수 있는 건 지금 이 글을 쓰고 있는 Chrome 브라우저 안에도 다음과 같이 캐시, 쿠키 등이 존재합니다.

     

    여기서 쿠키는 캐시와 비슷한(?) 기능이지만 인증에 관련한 작업을 하기 위한 목적성을 띄고요!

    캐시는 재사용될 것 같은 이미지, 영상 등 큰 리소스들을 임시로 들고 있는 것들이죠.

     

    자~~~ 그래서! 앱에서 이미지 캐싱은 이런 캐시에 이미지를 저장해뒀다가 나중에 로드할 때 먼저 캐시를 뒤져보고 있으면 가져오고 없으면 서버에서 불러오는 것입니다!

    캐시의 종류 2가지 - Memory Cache, Disk Cache

    근데 우리는 iOS 개발을 하면서 2가지의 캐시를 쓸 수 있습니다.

    하나는 메모리 캐시(Memory Cache)인데 얘는 우리가 RAM에 저장되는 애고 디스크 캐시에 비해 상대적으로 많이 저장이 불가능한 공간(주로 몇 MB 정도)이에요!

    그래서 공간이 부족하면 이전에 쓰던 메모리를 제거하고 올리게 됩니다.

     

    어? 그럼 이때 무슨 메모리 삭제함???????

    LRU(Least Recently Used) 방식으로 가장 오랜시간 접근하지 않은 데이터부터 삭제합니다!

     

    그리고 앱이 종료된다면 모든 데이터가 삭제되죠 ㅠㅠ('메모리'의 특성 상)

    하지만! 상당히 빠르다는 장점이 있습니다! 또한, 

     

    반면, 디스크 캐시는 말 그대로 디스크(ex. SSD, HDD)에 저장이 됩니다!

    앱에서는 다음과 같은 경로에 저장되는데,

    ~/Library/Caches/

     이 경로의 ~가 앱의 샌드박스 디렉토리이고, 이 안에 디스크 캐시가 존재합니다.

    (샌드박스는 플래시 메모리의 일종! SSD가 플래시 메모리 기반입니다ㅎㅎ TMI는 여기까지!)

    디스크는 보조 기억 장치라서 비휘발성이기에 데이터를 영구적으로 저장이 가능합니다.

     

    공간도 메모리 캐시에 비해서는 상대적으로 큰 편입니다.

    라이브러리나 설정에 따라 다르지만 일반적으론 수백 MB 정도로 보면 됩니다.

    이 공간 관리도 자동으로 알아서(이것도 메모리 캐시와 마찬가지로 LRU방식) 해주기 때문에 간편합니다.

     

    대신...얘는 메모리 캐시에 비해 느려요 ㅠㅠ

    다만 아예 디스크에서 데이터를 뒤지는 것보다+서버에서 직접 불러오는 것보다 훨씬 빠르죠..ㅎㅎ

    CPU, RAM, DISK들 사이에서 빠르게 접근을 하기 위해서 이 둘이 각각이 있는 것입니다!

     

    그래서 보통 어떤 Image에 대한 URL을 서버로부터 받아오면 메모리 캐시에 가서 있나보고, 없으면 디스크 캐시에 가서 있나보고, 없으면 서버에서 직접 불러오는 것입니다.

     

    이런 차이가 있다는 것을 생각하면서 정리해보면...

    1. 캐시에는 메모리 캐시와 디스크 캐시가 있다.
    2. 메모리 캐시는 빠르지만 앱이 종료되면 비워지고, 디스크 캐시는 느리지만 앱이 종료되어도 남아있다.
    3. Image 데이터를 처음에는 메모리 캐시에서 찾고, 없으면 디스크 캐시에서 찾고, 없으면 서버에서 받아온다.

     

    이 정도로 정리할 수 있겠죠?? ㅎㅎㅎㅎㅎ

     

    그럼 한번 제가 구현한 이미지 캐싱 앱을 보시죠!

    이미지 캐싱 앱 코드 GitHub 주소

    뭔 앱인데??

    간단하게 무슨 기능이 있는지 설명을 해보자면요...!!

    일단 iTunes Search API를 활용해서 앱 정보들을 받아오고,

    그 앱들을 목록으로 보여주는 앱입니다!

     

    그 과정에서 미리 받아온 앱 아이콘을 캐싱하는 과정을 확인해보려는 건데요!

    캐시에 저장을 Memory Cache에만, Disk Cache에만, 둘 다 저장 안하기, 둘 다 저장하기 총 4가지 경우로 나눠서 구현을 했습니다!

     

    이때 메모리 캐시는 NSCache로 만들고 / 디스크 캐시는 FileManager로 구현을 했습니다.

     

    그럼 한번 확인하러 가보겠습니다!

     

    메모리 캐시 vs 서버

    일단 앞서 쓴 것처럼 메모리 캐시에서 가져오는게 서버에서 가져오는 것보다 빠르겠죠...?

    아.무.래.도.

     

    이렇게 처음에 검색했을 땐 정보들이 메모리 캐시에 없으니 서버에서 가져오지만 제가 saveOption으로 .onlyMemory나 .both로 해두면 Memory에 저장이 되기 때문에 다시 스크롤을 올리면 메모리 캐시에서 가져오는 걸 확인할 수 있습니다.

     

    서버에서 가져오는 시간은 0.01~0.2초대 정도의 시간이 걸리지만,

    메모리 캐시에서 가져오는 시간은 0.00005초정도의 시간이 걸리는 것을 통해 확실히 서버에서 가져오는 것보다 메모리 캐시에서 가져오는게 빠르다는 걸 알 수 있습니다.

     

    그리고 메모리 캐시는 앱이 종료되면 데이터가 삭제된다고 했는데...

     

    이렇게 다시 실행하면 처음에 서버에서 데이터를 가져오는 것부터가 메모리 캐시에 저장이 안 되어있다는 걸 증명해주네요!

    디스크 캐시 VS 서버

    디스크 캐시도 마찬가지로 메모리 캐시에서 가져오는 것보다는 느리지만 서버에서 가져오는 것보다는 빠를 겁니다.

     

    위 테스트 결과도 saveOption을 .onlyDisk 나 .both로 한 결과인데,

    디스크 캐시에 저장이 되다보니 처음엔 서버에서 받아오지만 다시 위로 스크롤하니 디스크 캐시에서 가져오는 걸 확인할 수 있습니다.

     

    또한, 서버에서 가져오는 시간은 0.01~0.2초대 정도의 시간이 걸리지만,

    디스크 캐시에서 가져오는 시간은0.001~0.005초정도의 시간이 걸리는 것을 통해 이것도 메모리 캐시보다는 느리더라도 서버에서 가져오는 것보다 디스크 캐시에서 가져오는게 빠르다는 걸 알 수 있습니다.

     

    그리고 또 하나! 디스크 캐시는 앱이 종료되어도 계속 남아있다고 했죠?

     

    이렇게 앱을 종료하고 실행을 해서 위에 검색했던 '당근'을 검색한 내용들을 보니 처음부터 디스크 캐시에서 데이터를 가져오고 있습니다.

    물론 이전에 가져오지 않았던 아~~~~래에 있는 이미지들은 서버에서 가져오구요!

     

    이걸 통해 디스크 캐시에 있는 데이터들은 앱이 종료되어도 날아가지 않는다는 사실을 알 수 있습니다.

    KingFisher

    사실 이런 식으로 이미지 캐싱을 하는 걸 간단히 쓸 수 있도록 하는 써드 파티 라이브러리로 KingFisher란게 있습니다.

    아직 제대로 사용해보진 않았으나 앞서 제가 구현한 4가지 방식(onlyMemory, onlyDisk, both, none)을 바탕으로 손쉽게 이미지 캐싱을 구현할 수 있다고 하니 한번쯤 써봐야겠어요!

    이런 써드 파티 라이브러리 사용도 한번쯤 시간이 난다면 써보는 것도 꼭 필요한 학습이라고 생각이 드네요...!

    번외) iTunes Search API 관련 Tip

    일단 미리 iTunes Search API 관련해서 하나 말씀드리자면

    이 API는 어떤 검색어를 입력을 처음하면 데이터를 받아오고 이걸 기억하고 있다가,

    다음번에 호출하게 되면 빠르게 보내줍니다.

    그래서 다음과 같이 '템플런'이란 검색어를 13 mini라는 시뮬레이터에서 처음 검색한 결과와 두번째 검색한 결과가 한눈에 봐도 데이터를 수신하는 속도가 다릅니다.

    좌: 처음 검색 / 우: 2번째 검색

    마무리

    결론적으로 메모리 캐시 > 디스크 캐시 > 서버 순으로 데이터를 가져오는 속도가 빠르단 걸 알 수 있었습니다.

    또한, 메모리 캐시는 앱이 종료되면 데이터가 날아가고, 디스크 캐시는 그렇지 않단 것도 알 수 있었습니다.

     

    이걸 적용한다면 이미지 데이터를 재사용하는 과정에서 메모리를 덜 잡아먹을 수 있다는 장점을 가져갈 수 있습니다!

    또한 빠른 속도로 이미지를 가져올 수 있게 되어 유저에게 불편함을 줄여주고 한편으론 네트워크 사용량을 줄여주기에 데이터 요금사용량도 줄여줄 수 있습니다.

     

    이렇게 이미지 캐싱을 알아보았는데 앞으로 이미지를 많이 불러오는 작업이 필요해질 때는 이미지 캐싱 코드를 반드시 구현해봐야겠네요 ㅎㅎㅎ

     

    그럼 오늘도 긴 글 읽어주셔서 감사드리며 조만간 다시 좋은 포스팅으로 돌아오겠습니다!

    참고

    https://developer.apple.com/documentation/foundation/nscache

     

    NSCache | Apple Developer Documentation

    A mutable collection you use to temporarily store transient key-value pairs that are subject to eviction when resources are low.

    developer.apple.com

    https://velog.io/@o_joon_/Swift-Image-caching%EC%9D%B4%EB%AF%B8%EC%A7%80-%EC%BA%90%EC%8B%B1#%EB%8A%90%EB%82%80%EC%A0%90

     

    [Swift] Image caching(이미지 캐싱)

    Kingfisher 없이 이미지를 캐싱하는 법을 알아보자.

    velog.io

    https://hongssup.tistory.com/565

     

    [Swift iOS] 이미지 캐시 처리 Memory vs. Disk

    앱에서 사용되는 이미지가 많을 경우, 이미지를 매번 서버로부터 받아오면 로딩 속도도 오래걸리고 계속 네트워크 통신을 해주는 것도 리소스 낭비이기 때문에 이미지를 캐싱하는 작업을 해보

    hongssup.tistory.com

     


    아직 꼬꼬마 개발자입니다.

    더 나은 설명이나 코드가 있다면 언제든 환영입니다.

    적극적인 조언과 피드백 부탁드립니다!

     

    그럼 오늘도 개발 가득한 하루되세요!

    - Xerath -

    🤖🤖🤖🤖🤖🤖🤖

     

    728x90
    반응형