라이브러리 첫 도전
Jeongfisher는 저의 라이브러리 첫 번째 라이브러리입니다.
유명 라이브러리인 Kingfisher는 다들 아시죠?
이미지 캐싱, 다운로드, 편집 등 기능이 매우 많고 유용한 라이브러리입니다.
하지만 대부분의 앱에서는 이미지를 보여주고 캐싱하는 기능만 사용하는데요.
이점을 생각해서 Jeongfisher를 만들어보았습니다.
또한, 킹피셔는 하위 호환성을 고려해서 completionHandler를 이용해 비동기 처리를 합니다.
하지만 Jeongfisher는 iOS 13을 최소 버전으로 지정하여 Swift Concurrency를 적극 활용했습니다.
URLSession의 dataTask도 async/await을 지원하니 거리낄 게 없었죠 ㅎㅎ
현재 SPM 작업을 완료한 상태이고 (https://github.com/jeongju9216/Jeongfisher)
네이버 부스트캠프 웹·모바일 8기 멤버십 프로젝트에서 Kingfisher 대신 Jeongfisher를 사용해보려고 합니다 ㅋㅋ
혹시 Jeongfisher를 사용하시면서 혹은 포스팅을 읽으시면서 개선할 점을 말씀해 주시면 큰 도움 될 듯합니다!
Jeongfisher 특징
Jeongfisher는 아래 두 가지가 핵심입니다.
- URL로 메모리 캐시 -> 디스크 캐시 -> 네트워킹 순서로 캐시 데이터 확인
- 캐싱은 원본 이미지를 저장하고, UIImageView 크기에 맞게 Downsampling 진행
1번은 일반적인 이미지 캐싱 과정입니다.
메모리 캐시와 디스크 캐시를 직접 만들어서 각자의 장점을 살리려고 노력했습니다.
이 과정은 이후 작성될 개발일지를 통해 말씀드리겠습니다.
(여기서 보시면 됩니다 Jeongfisher 2. 메모리 캐시, 디스크 캐시)
2번은 이번 포스팅에서 다룰 내용입니다.
Jeongfisher는 다운샘플링이 기본 적용됩니다.
메모리 절약 이점이 화질 감소보다 더 크다고 생각했기 때문입니다.
Kingfisher는 사용자가 워낙 많아 자유도를 위해 다운샘플링을 진행하지 않지만,
Jeongfisher는 사용자가 적으니 이런 부분에선 자유로웠습니다 ㅎㅎ;;;
(물론 원본 이미지를 표시하는 메서드와 옵션도 구현했습니다!)
다운샘플링은 메모리 절약이 된다는 명확한 장점이 있습니다.
하지만 CPU 성능이나 이미지 설정 속도가 안 좋은게 아닐지 걱정이 되었습니다.
만약 다운샘플링 때문에 이미지가 천천히 표시된다면 적용을 안 하는게 나을테니까요 ㅠㅠ
정확한 성능 비교를 위해 XCTest를 이용해 테스트 해보았습니다.
Downsampling 화질 비교
성능 비교를 하기 전에 화질이 얼마나 차이가 나는지 보겠습니다.
아무리 성능이 좋아도 화질이 매우 안 좋다면 곤란하겠죠?
1000x1000 랜덤 사진으로 화질을 비교해 보겠습니다.
참고로 PC로 보면 이미지가 확대돼서 화질 체감이 클 수 있습니다 ㅎㅎ;
왼쪽이 다운샘플링 결과, 오른쪽이 원본 이미지입니다.
다운샘플링 결과가 흐릿하긴 하네요.
이젠 조금 더 작은 사이즈인 가로의 1/5 정사각형 크기로 비교해 보겠습니다.
왼쪽이 다운샘플링, 오른쪽이 원본입니다.
자세히 보면 차이가 있지만, 스크롤을 내리면서 본다고 생각했을 때 크게 체감이 되진 않습니다.
추가 내용)
위 사진은 다운샘플링을 UIImageView 크기와 동일하게 진행했습니다.
그런데 UIImageView 크기보다 1.2배, 1.5배처럼 약간 더 키워서 다운샘플링을 하면 화질이 개선되지 않을까 생각이 들더라고요.
왼쪽이 UIImageView의 1.5배 크기로 다운샘플링을 한 결과이고, 오른쪽이 원본입니다.
이제는 정말 비슷하지 않나요?
심지어 메모리는 기존과 비슷한 수준으로 측정되었습니다.
아주 좋군요👍
성능 측정
다운샘플링의 장점은 WWDC18 - Image and Graphics Best Practices에서 자세히 나와있습니다.
특히 메모리 관점에서 큰 이점이 있는데요.
위 WWDC 포스팅에서도 절반이 줄어들었고, Jeongfisher에서도 3배 이상 차이가 났습니다.
정확한 수치를 보기 위해 XCTest로 비교해 보았습니다.
테스트는 1000x1000 이미지 설정을 100번 수행하였고,
XCTClockMetric, XCTMemoryMetric, XCTCPUMetric를 추가하여 측정했습니다.
XCTest는 https://jeong9216.tistory.com/661에서 다루었으니 참고해 주세요.
수행 시간 (XCTClockMetric)
다운샘플링 과정 때문에 수행 시간이 느리지 않을까 걱정했습니다.
하지만 Clock Monotonic Time은 둘 다 0.00으로 동일했습니다.
하나하나 비교해 봐도 전혀 차이가 없네요.
느낌으로는 다운샘플링이 느릴 줄 알았는데 그게 아니었다는 걸 확인했습니다.
테스트가 중요하다는 걸 여기서 또 느낍니다 ㅎㅎ
메모리 성능 (XCTMemoryMetric)
먼저 Memory Peak Physical(최대 메모리 할당량)입니다.
둘은 생각보다 차이가 크지 않았습니다.
다운샘플링이 3MB 더 낮네요.
하지만 Memory Physical(평균 메모리 힐당량)은 큰 차이가 있었습니다.
다운샘플링 결과는 3.113, 원본은 11.633으로 3.6배 차이가 나네요.
Xcode 도구로 확인한 메모리 사용량도 확인해 봤습니다.
왼쪽부터 순서대로 다운샘플링, 원본, 킹피셔입니다.
다운샘플링의 메모리 사용량이 8배 낮다는 걸 볼 수 있네요.
킹피셔도 다운샘플링을 하지 않기 때문에 원본과 비슷한 결과를 보여줍니다.
이렇게 메모리에서는 다운샘플링이 압도적으로 유리하네요.
CPU 성능 (XCTCPUMetric)
CPU는 스크린샷을 찍진 않았습니다.
왜냐면 둘이 똑같았거든요!
CPU Cycles, CPU Instructions Retired, CPU Time 결과가 모두 같아서 굳이 스크린샷을 찍지 않았습니다.
결과 요약
정리해 보겠습니다.
왼쪽이 다운샘플링이고, 오른쪽이 원본입니다.
수행시간과 CPU는 크게 차이 없고, 평균 메모리 할당량은 다운샘플링이 3.6배 낮은걸 볼 수 있습니다.
참고로 킹피셔는 원본 결과와 비슷했습니다.
킹피셔는 다운샘플링을 하지 않기 때문에 원본과 비슷한 건 당연한 얘기겠네요.
결론
성능을 측정해 본 결과, 다운샘플링이 메모리 측면에서는 매우 유리하고, 화질 체감은 크지 않았습니다.
따라서 다운샘플링을 기본으로 적용한 건 좋은 선택이었다고 할 수 있겠네요.
물론 원본 이미지가 필요한 경우가 있을 겁니다.
이럴 때는 setOriginalImage 메서드나 옵션을 사용하면 됩니다.
느낌이 아니라 실제 성능을 테스트해 보고,
테스트 결과를 기준으로 기능을 구현하니 명확한 구현이 가능하다는 걸 배웠습니다.
이번에도 좋은 걸 배웠네요 ㅎㅎ
감사합니다.
아직은 초보 개발자입니다.
더 효율적인 코드 훈수 환영합니다!
공감과 댓글 부탁드립니다.