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

유사 문제 대응 기준

이 문제를 고친 뒤 관련 공식 자료를 찾아 읽으면서, 당시 코드에서 우연히 맞았던 부분과 규칙으로 남겨야 할 부분을 나눠 봤다.

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

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

다음에 상품 전환 이후 남은 이전 상태 같은 문제를 보면 아래 순서부터 확인하려고 한다.

  • 원본 값과 화면 파생 값의 소유자
  • 탭·계좌 변경 시 무효화할 요청
  • 이전 선택이 남는 캐시 범위
  • 같은 값이 여러 컴포넌트에서 바뀌는지

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

공식 참고 자료