Unity) Delegate(델리게이트) , Event(이벤트)
1. Delegate(델리게이트)
메서드 자체를 인자로 넘겨주는 형식 입니다. (함수 x)
public delegate void ScoreChangedHandler(int score);
private void Start()
{
_scoreChanged = PrintScore;
_scoreChanged.Invoke(10);
}
하지만, 델리게이트를 직접 선언하는 경우보다는
뒤에 나올 ==Action==과 ==Func== 을 사용을 하는 경우가 많다.
1-1) Invoke
델리게이트 객체가 참조하고 있는 실제 메서드를 안전하고 명시적으로 실행시키는 명령어 입니다.
- Invoke가 없어도 실행이 가능하지만, delegate와 일반 함수를 구분할 수 있어 가독성이 높아집니다.
del(10,20)과del.Invoke(10,20)는 내부적으로 완전히 같습니다.
1-2) 델리게이트 체인
여러 함수들을 델리게이트 함수에 할당해놓고 순서대로 호출하는 형식입니다.
==+=로 더하고-=== 로 뺍니다.
private ScoreChangedHandler _scoreChanged;
// 담기
_scoreChanged += PrintScore;
_scoreChanged += SaveScore;
// 떼기
_scoreChanged -= SaveScore;
- 비어 있는 delegate를 부르면 NullReferenceException 이 발생하기 때문에
==if 형식의 조건문==이나 null조건부 연산자인 ==scoreChanged?.Invoke(_score);== 로 null 체크를 해주는 것이 좋습니다.
| 상황 | 무슨 일이 일어나나 |
|---|---|
담은 적 없는 메서드를 -=로 뺀다 | 아무 일도 일어나지 않는다. 오류가 나지 않는다 |
같은 메서드를 +=로 두 번 더한다 | 두 번 담기고 부를 때 두 번 불린다 |
두 번 담긴 것을 -=로 한 번 뺀다 | 하나만 빠진다. 뒤쪽에 담긴 것부터 빠진다 |
1-3) Action, Func
매개변수의 반환형의 조합마다 ==delegate== 줄을 새로 쓰는 일은 번거롭기 때문에 자주 쓰는 조합이 이미 만들어져있습니다.
System 네임스페이스에 있어, ==using System;== 이 필요합니다.
| 이름 | 반환값 |
|---|---|
Action | 없다 |
Func | 있다 |
- ==Action== 은 반환값이 없는 메서드를 담습니다.
| 형태 | 담을 수 있는 메서드 |
|---|---|
Action | 매개변수가 없고 반환값이 없는 것 |
Action<int> | int 하나를 받고 반환값이 없는 것 |
Action<int, string> | int와 string을 받고 반환값이 없는 것 |
private Action<int> _scoreChanged;
private void Start()
{
_scoreChanged += PrintScore;
_scoreChanged.Invoke(10);
}
- ==Func== 은 반환값이 있는 메서드를 담습니다.
| 형태 | 담을 수 있는 메서드 |
|---|---|
Func<int> | 매개변수가 없고 int를 돌려주는 것 |
Func<int, bool> | int 하나를 받고 bool을 돌려주는 것 |
Func<int, string, bool> | int와 string을 받고 bool을 돌려주는 것 |
※ 반환값이 있는 델리게이트에 여럿을 담으면 마지막 것의 값만 남습니다.
여럿이 나눠 받는 알림에는 ==Func== 을 쓰진 않기 때문에 게임코드에서 압도적으로 쓰는 것은 ==Action== 입니다.
2. Event (이벤트)
public 으로 델리게이트를 열어놓게 되면 외부에서 쉽게 변경이 가능해 문제가 발생할 수 있습니다.
필드 앞에 ==event== 를 붙여 외부에서 할 수 있는 일들을 줄여 리스너를 더하고 빼는 것만 됩니다.
| 밖에서 하는 일 | event 없을 때 | event 있을 때 |
|---|---|---|
+=로 더하기 | 된다 | 된다 |
-=로 빼기 | 된다 | 된다 |
=로 대입하기 | 된다 | 막힌다 |
Invoke로 부르기 | 된다 | 막힌다 |
2-1) 구독과 해제
구독과 해제는 ==OnEnable== , ==OnDisalbe== 에서 합니다.
오브젝트가 켜져 있는 동안에만 알람을 받습니다.
- 이벤트 이름은 ==OnScoreChanged== 처럼 On 을 붙인 PascalCase 로 보통 사용합니다.
==ScoreManager.Instance.OnScoreChanged += OnScoreChanged;==
왼쪽은 상대가 가진 이벤트 이고, 오른쪽은 내 클래스의 메서드 입니다.
직접 부르는 형태 | 이벤트 형태 | |
|---|---|---|
알릴 곳이 하나 늘 때 |
| 새로 만든 쪽에서 걸기만 한다 |
점수 매니저가 아는 것 | 받는 쪽의 클래스 이름과 메서드 이름 | 아무것도 모른다 |
받는 쪽이 아는 것 | 아무것도 모른다 | 점수 매니저와 그 이벤트 이름 |
붙이는 자리 | 한 오브젝트에 함께 있어야 한다 | 어디에 있어도 된다 |
using System;
using UnityEngine;
public class ScoreManager : MonoBehaviour
{
private int _score;
public static ScoreManager Instance { get; private set; }
public event Action<int> OnScoreChanged;
private void Awake()
{
SetSingleton();
}
public void AddScore(int amount)
{
_score += amount;
if (OnScoreChanged != null)
{
OnScoreChanged.Invoke(_score);
}
}
private void SetSingleton()
{
Instance = this;
}
}

