Cheondi
개발 · Unity

미니차트 첫 로딩 정지 원인

차트 창은 열렸지만 초기 데이터와 화면 준비 순서가 어긋나 로딩이 끝나지 않던 문제를 추적했습니다.

  • #unity
  • #loading
  • #initialization

내역 항목을 누르면 작은 차트가 열렸다. 두 번째부터는 잘 열리는데 앱을 실행한 뒤 처음 누를 때만 로딩에서 멈추는 경우가 있었다. 한 번 닫았다 다시 열면 정상이라 데이터 자체가 틀린 것 같지는 않았다.

처음에는 첫 요청이 느린 문제로 생각했다. 요청 로그에는 정상 응답이 남아 있었다. 응답은 왔지만 차트를 그릴 컴포넌트가 아직 초기화되지 않은 시점에 데이터가 적용되고 있었다.

다중 준비 완료 조건

차트를 보여 주려면 적어도 세 가지가 준비돼야 했다.

  • 패널과 그래프 컴포넌트 생성
  • 선택 항목 정보 확정
  • 차트 데이터 응답 완료

각각 비동기로 움직이는데 마지막으로 끝난 작업이 누구인지에 따라 그리기 함수가 호출되지 않았다.

void TryRender()
{
    if (!viewReady || !selectionReady || chartData == null)
        return;

    RenderChart(chartData);
    HideLoading();
}

각 준비 단계가 끝날 때 TryRender()를 부르면 완료 순서와 관계없이 모든 조건이 갖춰진 순간 한 번 그릴 수 있었다.

분산된 로딩 종료 책임

성공 콜백에서는 로딩을 끄지만, 빈 데이터나 화면이 먼저 닫힌 경우에는 그대로 남았다. 로딩 표시를 켠 코드와 끄는 코드가 멀리 떨어져 있어 빠진 경로를 찾기 어려웠다.

그래서 Loading, Ready, Empty, Failed 상태에 따라 한 함수가 표시를 결정하도록 모았다. 무조건 HideLoading()을 추가하는 것보다 어떤 상태로 끝났는지를 명확히 하는 편이 이후 오류도 줄였다.

첫 실행 전용 경로

두 번째부터 잘 되는 건 이미 생성된 리소스와 캐시 덕분이었다. 첫 실행은 폰트, 프리팹과 데이터 준비가 모두 겹쳤다. 두 번째 성공을 정상 증거로 보면 초기화 문제를 놓치기 쉬웠다.

테스트할 때 캐시와 화면 인스턴스를 완전히 초기화하고 첫 진입을 반복했다. 네트워크 지연도 넣어 준비 순서를 바꿔 봤다. 순서가 바뀌어도 결과가 같아야 초기화 흐름이 안정적이라고 볼 수 있었다.

상태 표현으로서의 로딩 화면

예전에는 로딩 이미지를 요청 전후에 켜고 끄는 장식으로 생각했다. 이번 문제를 겪으며 로딩도 화면 상태의 결과라는 걸 알았다. 무엇을 기다리는지 정의하지 않으면 영원히 돌거나 너무 일찍 사라진다.

미니차트가 처음에만 멈춘 문제를 고치며 초기화 순서, 여러 준비 조건과 로딩 책임을 같이 보게 됐다. 이후 “두 번째에는 돼요”라는 증상이 나오면 캐시보다 먼저 첫 생명주기의 순서를 의심한다.

기술 문서 기반의 책임 경계

작업 당시에는 눈앞의 오류를 먼저 고쳤지만, 이후 기술 문서와 맞춰 보며 확인 순서를 조금 더 구체화했다.

Unity 실행 순서 문서는 Awake, OnEnable, Start, Update 같은 엔진 이벤트가 어느 구간에서 호출되는지 설명한다. 하지만 로딩·성공·빈 결과·실패 같은 업무 상태의 순서까지 대신 정해 주지는 않는다. 두 종류의 순서를 섞어 생각하면 콜백이 한 프레임 늦게 왔다는 이유만으로 이전 화면 상태가 다시 살아날 수 있다.

그래서 수명주기 메서드는 상태 전이를 직접 흩어 놓는 장소보다, 한 곳에 모인 전이 함수를 호출하는 경계로 쓰는 편이 추적하기 쉬웠다.

다음에 미니차트 첫 로딩 정지 원인 같은 문제를 보면 아래 순서부터 확인하려고 한다.

  • 요청 시작과 종료가 정확히 한 번 짝을 이루는지
  • 빈 결과와 오류의 표시 차이
  • 취소된 요청이 로딩을 다시 켜는지
  • 타임아웃 뒤 사용자 재시도 경로

새 응답을 적용하기 전에 요청 식별자와 현재 선택 조건이 여전히 같은지 확인해야 오래된 응답을 버릴 수 있다.

공식 참고 자료