Cheondi
개발 · Unity

화면을 바꿨는데 이전 상태가 따라왔다

서로 다른 상품 화면을 전환할 때 이전 패널과 선택 상태가 남는 문제를 이벤트 순서로 풀어 본 기록입니다.

  • #unity
  • #state
  • #lifecycle

비슷한 내역을 보여 주는 두 상품 화면을 전환하는 기능을 수정한 적이 있다. 버튼을 누르면 기존 패널을 끄고 새 패널을 켜는 정도로 생각했다. 실제 화면에서도 대부분 잘 바뀌었다. 문제는 여러 번 빠르게 전환하거나, 상세 패널을 연 상태에서 바꿀 때 나타났다.

새 화면은 열렸는데 이전 상품의 상세 패널이 남아 있거나, 스크롤 위치와 선택 항목이 그대로 따라왔다. 가끔은 두 패널이 잠깐 겹치면서 버벅이기도 했다. 눈에 보이는 오브젝트만 바꿨고 화면이 갖고 있던 상태는 정리하지 않았기 때문이었다.

SetActive만으로 끝나지 않았다

처음 코드는 아주 단순했다.

oldPanel.SetActive(false);
newPanel.SetActive(true);

하지만 패널 안에는 선택한 항목, 열린 상세 영역, 스크롤 위치, 마지막 요청 결과가 남아 있었다. GameObject가 꺼졌다고 그 값들이 초기화되는 건 아니었다. 다시 켜면 이전 상태가 그대로 살아났다.

처음에는 OnEnable()에서 모든 값을 초기화했다. 그러자 잠깐 다른 화면을 보고 돌아왔을 때 사용자가 보던 위치까지 사라졌다. 어떤 값은 유지해야 했고 어떤 값은 상품이 바뀌면 버려야 했다.

유지할 상태와 버릴 상태를 나눴다

종이에 상태를 두 종류로 나눠 적었다.

  • 화면을 잠깐 닫아도 유지할 값: 스크롤 위치, 정렬 방식
  • 상품이나 계좌가 바뀌면 버릴 값: 선택한 주문, 열린 상세 패널, 이전 응답

이 구분을 한 뒤부터 Reset() 하나로 모두 지우는 대신 전환 이유를 넘겨 처리하는 방식이 이해됐다.

void Close(ViewChangeReason reason)
{
    selectedItem = null;
    detailPanel.SetActive(false);

    if (reason == ViewChangeReason.AccountChanged)
        cachedRows.Clear();
}

예시는 단순화했지만 핵심은 닫힌다는 결과만 보지 않고 왜 닫혔는지를 함께 보는 것이었다.

이벤트가 두 번 오는 경우도 있었다

전환 버튼이 화면 변경 이벤트를 보내고, 계좌 변경 쪽에서도 비슷한 갱신 이벤트를 보내는 경우가 있었다. 둘이 거의 동시에 오면 한쪽은 데이터를 비우고 다른 쪽은 이전 응답을 다시 그렸다. 최종 화면만 보면 랜덤하게 보였다.

로그에 프레임 번호와 이벤트 이름을 함께 찍어 보니 같은 갱신 함수가 짧은 시간에 두 번 호출되는 게 보였다. 그제야 버그가 값의 문제가 아니라 이벤트 순서의 문제라는 걸 알았다. 중복 호출을 막거나, 마지막으로 선택된 화면인지 확인한 뒤 결과를 적용하는 장치가 필요했다.

전환은 작은 생명주기였다

이 경험 이후 탭이나 화면 전환을 단순한 켜기/끄기로 보지 않게 됐다. 닫기 전 정리, 전환 원인 기록, 새 요청 시작, 늦게 도착한 이전 응답 무시까지 하나의 생명주기로 본다.

Unity의 OnEnable, OnDisable을 안다고 해서 화면 생명주기를 이해한 건 아니었다. 프로젝트가 어떤 이벤트를 보내고 어떤 값을 유지하기로 했는지까지 알아야 했다. 이전 상태가 따라오던 버그는 그 차이를 처음 체감하게 해 준 문제였다.