[2025_12_30] Unity UI 이벤트 구독/해제
2025. 12. 30. 21:09ㆍTIL
TIL - Unity UI 이벤트 구독/해제
문제 상황
증상:
- 미션 패널에서 개별 Claim 버튼을 눌러도 아무 반응이 없음
- 하지만 Claim All 버튼은 정상 작동
- 에디터를 재시작하거나 패널을 다시 열어도 동일한 문제 발생
혼란스러웠던 점:
- OnRewardItemRequested?.Invoke()는 호출됨 (로그 확인)
- 하지만 핸들러인 OnRewardClaimHandler()는 실행 안됨
- 이벤트 구독은 InitializeCards()에서 명확히 했는데 왜 안 되는지 이해 불가
csharp
// UIMissionCard.cs
private void OnButtonClicked()
{
if (isCompleted)
{
Debug.Log("Claim 이벤트 발동!"); // 로그 찍힘
OnRewardItemRequested?.Invoke(MissionIndex); // 실행됨
}
}
// UIMissionPanel.cs
private void OnRewardClaimHandler(int missionIndex)
{
Debug.Log("핸들러 호출!"); // 여기는 실행 안됨!
// ...
}
원인 분석
UIBase를 상속받은 UI는 다음과 같은 라이프사이클을 가짐:
csharp
// 최초 1회
SetupUI() → SubscribeEvents()
// 패널 열 때마다
OnShow()
// 패널 닫을 때마다
OnHide() → (내부적으로) UnsubscribeEvents()
// 파괴 시
OnDestroy() → UnsubscribeEvents()
2. 잘못된 이벤트 구독 시점
csharp
// UIMissionPanel.cs
protected override void SetupUI()
{
InitializeCards(); // ← 여기서 카드 생성 + 이벤트 구독
}
private void InitializeCards()
{
foreach (var questData in dailyMissions)
{
var card = Instantiate(dailyCardPrefab, dailyCardContainer).GetComponent<UIMissionCard>();
card.Init(questData);
SubscribeCardEvents(card); // 최초 1회 구독
dailyCards.Add(card);
}
}
protected override void UnsubscribeEvents()
{
// 패널이 닫힐 때 자동 호출됨!
foreach (var card in dailyCards)
UnsubscribeCardEvents(card); // 이벤트 해제!
}
protected override void OnShow()
{
// 패널이 다시 열릴 때
UpdateTabUI(currentTabIndex);
UpdateClaimAllButton();
// 이벤트 재구독 없음!
}
문제:
- 최초에는 이벤트 구독됨
- 패널 닫으면 UnsubscribeEvents() 자동 호출 → 이벤트 해제
- 패널 다시 열면 OnShow() 호출 → 이벤트 재구독 안함
- 카드 이벤트는 null 상태로 남음!
3. Claim All은 왜 작동했나?
csharp
private void OnClaimAllButtonClicked()
{
var dailyMissions = missionManager.GetDailyMissions();
foreach (var (data, progress) in dailyMissions)
{
missionManager.ClaimReward(data.index); // ← 직접 호출!
card.SetCardClaimed();
}
}
Claim All은 이벤트를 사용하지 않고 직접 메서드를 호출하기 때문에 정상 작동!
해결 방법
수정된 코드
csharp
// UIMissionPanel.cs
protected override void SetupUI()
{
InitializeCards(); // 카드만 생성 (이벤트 구독 X)
}
private void InitializeCards()
{
foreach (var questData in dailyMissions)
{
var card = Instantiate(dailyCardPrefab, dailyCardContainer).GetComponent<UIMissionCard>();
card.Init(questData);
// SubscribeCardEvents(card); // 여기서 구독하지 않음!
dailyCards.Add(card);
}
}
protected override void OnShow()
{
base.OnShow();
UpdateTabUI(currentTabIndex);
UpdateClaimAllButton();
// 패널이 열릴 때마다 이벤트 구독!
SubscribeAllCardEvents();
}
현재 프로젝트 이벤트 관리
- 영구적 이벤트: SubscribeEvents()에서 구독 (MissionManager 이벤트, 버튼 onClick 등)
- 일시적 이벤트: OnShow()에서 구독, OnHide()/UnsubscribeEvents()에서 해제 (카드 이벤트 등)
현재 프로젝트 Unity UI 패턴이벤트 종류구독 시점해제 시점예시Global SubscribeEvents() UnsubscribeEvents() MissionManager 이벤트 Button SubscribeEvents() UnsubscribeEvents() onClick Dynamic OnShow() OnHide()/UnsubscribeEvents() 동적 생성 카드 이벤트 교훈: 이벤트 구독/해제 시점을 명확히 설계하자!
'TIL' 카테고리의 다른 글
| [2026_01_02] 중간 발표 (0) | 2026.01.02 |
|---|---|
| [2025_12_31] Unity 게임 배속 증가 시 Projectile 충돌 감지 실패 해결 (1) | 2025.12.31 |
| [2025_12-29] 유닛 떨림 현상 해결 - 유닛 회피 시스템 (0) | 2025.12.29 |
| [2025_12_26] 공격 범위 계산 버그 - 좌표 기준점 설정의 중요점 (0) | 2025.12.26 |
| [2025_12_24] 컴포지션 패턴 (0) | 2025.12.24 |