[TIL/23] 비동기초기화 생성자 트러블슈팅

안건우·2025년 11월 5일

sparta_til

목록 보기
22/26

문제 상황

EnemyPresenter와 EnemyView는 정상 작동하지만, EnemyView의 HP와 Stamina UI만 업데이트되지 않는 기묘한 현상이 발생했다.

같은 CharacterView와 CharacterPresenter를 상속받는 PlayerPresenter 쪽은 문제없이 작동하는데, Enemy 쪽만 UI가 반응하지 않았다.

원인 분석

문제의 핵심은 EnemyPresenter가 바라보는 Model과 EnemyView가 바라보는 Model이 서로 달랐다는 점이다.

PlayerPresenter vs EnemyPresenter의 차이점

PlayerPresenter의 경우:

  • Player Model이 GameLifetimeScope에 등록되어 있음
  • Presenter가 생성될 때 이미 Model이 준비된 상태
  • DI 컨테이너가 자동으로 Model을 주입

EnemyPresenter의 경우:

  • Enemy Model은 배틀 씬 생성 시 ResourceManager를 통해 비동기적으로 로드됨
  • Presenter 생성 시점에는 실제 Enemy Model이 존재하지 않음
  • 어쩔 수 없이 BattleSceneLifetimeScope에 더미 객체를 등록
// 문제가 있던 코드
builder.Register(resolver => new Enemy(), Lifetime.Scoped);

이후 BattleService에서 실제 Enemy가 로드되면 SetEnemy()를 호출해 Presenter의 Model을 교체하는 방식을 사용했다.

결과적으로 EnemyPresenter는 실제 Enemy를, EnemyView는 더미 Enemy를 참조하는 상황이 발생했다.

해결 과정

1차 시도: SetEnemy에서 재연결

SetEnemy() 메서드에서 이벤트 구독과 View-Model 연결을 다시 수행했다.

public void SetEnemy(Enemy enemy)
{
    _model = enemy;
    // 이벤트 재구독
    // View와 Model 재연결
}

동작은 하지만 찝찝했다. 생성자에서 한 번 연결했는데 또 다시 연결하는 게 깔끔하지 않았다.

2차 시도: 구조 개선

CharacterPresenter의 책임 분리:

  • CharacterPresenter는 생성자에서 View만 받도록 변경
  • Model 주입은 PlayerPresenterEnemyPresenter가 각자 처리
// CharacterPresenter - 추상 클래스
public abstract class CharacterPresenter
{
    protected CharacterView _view;
    
    protected CharacterPresenter(CharacterView view)
    {
        _view = view;
    }
}

// PlayerPresenter - Player Model은 DI로 주입
public class PlayerPresenter : CharacterPresenter
{
    public PlayerPresenter(PlayerView view, Player model) : base(view)
    {
        // Model 초기화
    }
}

// EnemyPresenter - Model은 나중에 설정
public class EnemyPresenter : CharacterPresenter
{
    public EnemyPresenter(EnemyView view) : base(view)
    {
    }
    
    public void SetEnemy(Enemy enemy)
    {
        // 최초 Model 설정
    }
}

BattleSceneLifetimeScope 정리:

  • 더미 Enemy 객체 생성 코드 삭제
  • EnemyPresenter는 View만 받아서 생성

결과

  • EnemyPresenter와 EnemyView가 동일한 Model을 바라보게 됨
  • UI 업데이트 정상 작동
  • 더미 객체 생성이라는 불필요한 과정 제거
  • 코드 구조가 더 명확해짐

배운 점

  • 비동기 로드되는 리소스를 DI 컨테이너에 등록할 때는 신중해야 한다.
  • 더미 객체로 우회하는 것보다는, 애초에 Presenter가 Model 없이도 생성될 수 있도록 설계하고, 나중에 실제 Model을 주입받는 구조가 더 안전하다.
  • VContainer의 Lifetime과 객체 생성 시점을 정확히 이해하고 설계하는 것이 중요하다는 걸 다시 한번 느꼈다.

0개의 댓글