개발

SMART LOTTO 개발기 4편 — 통계 화면이 느렸던 이유, Dictionary로 해결한 방법

2026-01-31·2분 읽기
SMART LOTTO 개발기 4편 — 통계 화면이 느렸던 이유, Dictionary로 해결한 방법

데이터는 쌓였는데 화면이 버벅인다

Realm에 로또 당첨 데이터를 전부 저장하는 데는 성공했습니다. 당시 기준으로 약 1,000회, 이후 업데이트되며 1,200회가 넘었습니다.

문제는 통계 화면을 열 때였습니다.

1번부터 45번까지 각 번호가 1등 당첨에 몇 번씩 등장했는지를 보여주는 화면. 화면을 열 때마다 Realm에서 전체 데이터를 불러와서 반복문을 돌렸더니 체감할 수 있을 만큼 느렸습니다.


SMART LOTTO 통계 화면

문제의 코드

단순하게 짜면 이런 형태가 됩니다.

let allResults = realm.objects(LottoResult.self)
var frequency: [Int: Int] = [:]

for result in allResults {
    let numbers = [result.num1, result.num2, result.num3,
                   result.num4, result.num5, result.num6]
    for num in numbers {
        frequency[num, default: 0] += 1
    }
}

1,200개 회차 × 6개 번호 = 7,200번의 반복. 이게 화면을 열 때마다 실행됩니다.

단순 반복 횟수로는 많지 않아 보이지만, Realm 객체를 1,200개 전부 메모리에 올리고 각 속성에 접근하는 오버헤드가 쌓이면 체감 속도에 영향을 줍니다.


해결책: 미리 계산해서 Dictionary에 담아두기

핵심은 "화면을 열 때마다 계산하지 말자"였습니다.

방법은 이렇습니다. 앱 실행 시점 또는 데이터가 갱신될 때 한 번만 전체 집계를 수행하고, 그 결과를 [Int: Int] 형태의 Dictionary로 만들어 메모리에 유지합니다.

// 앱 실행 시 한 번만 수행
var numberFrequency: [Int: Int] = [:]
let allResults = realm.objects(LottoResult.self)

for result in allResults {
    [result.num1, result.num2, result.num3,
     result.num4, result.num5, result.num6].forEach {
        numberFrequency[$0, default: 0] += 1
    }
}

이후 통계 화면에서는 Realm을 다시 건드리지 않습니다. numberFrequency[7] 이런 식으로 Dictionary에서 바로 꺼내씁니다.


Dictionary 조회가 Array보다 빠른 이유

배열로 45개 원소를 순서대로 저장하면, 특정 번호의 빈도를 찾으려면 인덱스를 알거나 처음부터 탐색해야 합니다. 최악의 경우 O(n).

Dictionary는 키로 바로 값에 접근합니다. O(1). 번호 자체를 키로 쓰면 몇 번 번호이든 즉시 값을 꺼낼 수 있습니다.

45개짜리 배열에서 O(n)과 O(1)의 차이는 크지 않지만, 이 조회가 차트를 그리거나 정렬 로직이 돌아갈 때 반복해서 일어나면 누적 차이가 생깁니다. 그리고 무엇보다 코드가 훨씬 명확해집니다.


캐싱 패턴이 준 교훈

이 작업이 별거 아닌 것처럼 보이지만, 여기서 배운 개념이 이후 개발에 계속 쓰였습니다.

"매번 계산하지 말고, 한 번 계산한 걸 재사용하자."

특히 모바일 앱에서는 CPU나 메모리를 아끼는 게 배터리와 직결됩니다. 사용자는 앱이 전력을 많이 쓴다고 느끼면 앱을 지웁니다. 성능 최적화는 사용자 경험의 일부입니다.

다음 편에서는 사용자 리뷰에서 직접 기능 아이디어를 받아 업데이트한 이야기를 해보겠습니다.