[CaloLink] - 이미지 로딩 최적화

sunghun kim·2025년 8월 15일

[캡디 - CaloLink]

목록 보기
9/9

문제 상황

ProductListCell과 DetailViewController의 이미지를 불러오기 위해 아래와 같은 원시적인 방법을 사용했다.

DispatchQueue.global().async {
    if let data = try? Data(contentsOf: imageURL), let image = UIImage(data: data) {
        DispatchQueue.main.async {
            self.productImageView.image = image
        }
    }
}

이 코드는 일단 동작은 하지만, 실제 앱 환경에서 사용하기에는 다음과 같은 문제점들을 가지고 있었다.

  • 캐싱의 부재
    • 이미 한번 다운로드한 이미지를 저장해두지 않는다.
    • 사용자가 스크롤을 내려갔다가 다시 올라오면, 똑같은 이미지를 불필요하게 다시 다운로드해야 한다.
    • 이는 사용자 데이터 낭비와 느린 로딩속도의 직접적인 원인이 된다.
  • 셀 재사용 오류 가능성
    • UITableView는 스크롤시 재사용된다.
    • 이미지 다운로드가 끝나기 전에 사용자가 빠르게 스크롤하면, 다운로드가 완료된 이미지가 엉뚱한 셀에 표시가 될 수 있는 버그가 존재한다.
  • 비효율적인 비동기 처리
    • Data(contentsOf:)는 동기함수로, 데이터 수신이 완료될 때까지 해당 스레드를 차단한다.
    • 지금은 global() 스레드에서 실행하여 앱이 멈추지는 않지만 현대적인 비동기 처리방식은 아니라고 한다.

대안 분석

직접 구현

  • 방법
    • URLSession을 사용하여 비동기적으로 이미지를 다운로드하고, NSCache를 사용하여 메모리 및 디스크 캐시 시스템을 직접 구축하는 방식.
  • 장점
    • 외부 라이브러리에 대한 의존성이 없다.
    • 네트워크 및 캐싱의 동작 원리를 깊이 있게 학습할 수 있다.
  • 단점
    • 높은 구현 비용: 안정적인 캐시 시스템을 직접 만드는 데는 상당한 시간과 노력이 필요하다.

외부 라이브러리 사용

  • 방법
    • Kingfisher, Nuke 등 iOS 생태계에서 널리 사용되고 검증된 이미지 로딩 라이브러리를 도입하는 방식.
  • 장점
    • 압도적인 생산성: `imageView.kf.setImage(with: url) 단 한줄의 코드로 비동기 로딩, 캐싱, 플레이스홀더 설정 등 모든 복잡한 작업을 처리할 수 있다.
    • 높은 성능과 안정성: 수많은 앱에서 사용되며 최적화되고 검증된 솔루션이다. 셀 재사용 문제 등 고려해야할 모든 예외 케이스가 이미 처리되어 있다.
    • 풍부한 기능: 이미지 전환 효과, 리사이징, 필터 적용 등 다양한 부가 기능을 쉽게 사용할 수 있다.
  • 단점
    • 프로젝트 외부 의존성이 추가된다.

최종 결정

Kingfisher

Kingfisher 라이브러리를 사용하기로 결정했다.

직접 구현하는 방식의 학습적 가치도 있지만, 개인적인 프로젝트의 목표는 "완성하고 개선하기"이다.
Kingfisher를 사용함으로써 얻는 개발 시간 단축, 성능 및 안정성 확보라는 이점이 "외부 의존성 추가"라는 단점을 압도적으로 상회한다고 판단했다.

profile
기죽지않기

0개의 댓글