멀티 스레딩 환경 또는 다른 백그라운드 작업에서 어떤 일을 시키고 끝났는지 확인해야 하는 경우가 있습니다.
일이 끝났니?
첫 번째 방법으로는 주기적으로 일을 다 끝냈는지 체크하는 방식이 있습니다.
주기가 짧을수록 체크하는 횟수가 많아지고, 그만큼 일이 종료됐는지 빨리 체크할 수 있지만 언제 종료될지 모르는 일을 체크하기 위해 반복문으로 끊임없이 체크해야 합니다. 이는 자원 낭비로도 이어질 수 있습니다.
반대로 주기를 길게 두고 체크한다면 끝나는것은 감지하겠지만 정확히 어느 시점에 끝났는지 감지하는 것은 어려울 것입니다.
소스 예제는 아래와 비슷한 상황일 것 같습니다.
|
|
일이 끝나면..
일이 끝나면 해야할 일들을 미리 알려주는 겁니다. 따라서 위 방식처럼 일이 끝났는지 체크하기 위한 로직 자체가 필요 없다는 뜻입니다.
일을 하는 주체는 끝나자 마자 미리 전달 받은 일을 진행함으로서 체크 주기마다 달라졌던 딜레이도 없을 것입니다!
|
|
일이 끝난 후 해야할 일을 함수로 정의했고, 이 함수를 백그라운드에서 돌아가는 DoSomething()
메서드 끝에 실행해주고 있습니다.
여기서 onSomething
이 바로 콜백함수 되겠습니다. 😄
💡
OnClick()
OnKeyDown()
OnClose()
등 콜백함수는 보통On
으로 시작합니다.
🚀 Delegate
C# 에서는 C/C++ 처럼 어떤 함수를 변수처럼 보관해 주는 함수 포인터 개념이 바로 Delegate 입니다.
C 에서는 구조체에 함수 포인터를 넣음으로서 오늘날의 Class 개념(멤버 변수 및 메서드)을 구현했고, 위 예시처럼 콜백에서도 사용 되었었습니다.
Delegate 는 이처럼 함수 포인터처럼 함수의 내용을 변수처럼 저장하고 있다가 그 변수를 참조하여 함수를 호출도 하며, 컨테이너처럼 작동하여 여러 함수를 가리킬 수도 있습니다.
💡
Action
과Func
와 같은 자료형은 모두 Delegate를 이용하여 만든 템플릿입니다!Action
은 Return 타입이 없는 함수형,Func
는 Return 타입이 있는 함수형으로 구분 됩니다. Delegate를 직접 만들어서 사용해도 되지만 위 두 자료형을 사용하시는 것이 편리합니다.
|
|
💡 함수 포인터에 아무것도 할당하지 않고(is null) 그 포인터를 참조하여 함수 호출을 할 경우 널 포인트 오류가 나는 것은 Delegate 도 똑같습니다! 따라서
onSomething?.Invoke();
와 같은 형태로 사용하시는 것을 권장 드립니다.
예시 상황
- 캐릭터가 어느 오브젝트에 닿았을 때를 감지하여 어떤 행동을 해야한다.
- 유니티에서는
OnCollisionEnter()
OnTriggerEnter()
등이 있습니다.
- 유니티에서는
- 사용자가 어떤 설정을 변경했을 때 어떤 행동을 해야한다.
OnChangeVolue()
과 같이 만들면 되겠죠?
- 어떤 작업을 백그라운드(스레드풀과 같은) 처리를 했는데, 이 때 나온 결과로 무엇을 해야한다.
Action
이 아닌Func
로 만들어서 호출해주면 되겠죠?
위와 같이 콜백을 등록하여 호출하면 매우 편리하며 종속 관계도 많이 줄일 수 있어서 좋습니다! 😎