언리얼의 Delegate(델리게이트), multiCastDelegate(멀티캐스트 델리게이트),DynamicDelegate(다이나믹 델리게이트)
그리고 Event(이벤트)에대해 알아보겠습니다.
Delegate는 C++오브젝트 상의 멤버함수를 안전하게 호출할수 있는 기능이다.
Delegate로 지정한 오브젝트의 멤버함수를 동적으로 바인딩 시킬수있어 유동적으로 사용가능하다.
Delegate는 호출하고자하는 함수를 갖고있는 오브젝트의 유형을 알필요가없다.
Delegate를 사용할때 값 전달이 가능하지만 이때 heap메모리에 할당하기에 참조 전달 방식이 권장된다.
Delegate는 싱글 캐스트, 멀티 캐스트 둘다지원한다.
MultiCastDelegate는 SingleCastDelegate의 특징을 대부분 갖지만 1대n을 관리할때 사용된다.
MultiCastDelegate는 반환값을 사용할수없다.(여러 객체마다 반환하는값이 다르기때문에)
DynamicDelegate는 Delegate와 일반적으로 비슷하지만
Delegate는 빌드타임에 바인딩이 이루어지고 런타임에서는 바인딩 수정이 불가능하다.
DynamicDelegate는 런타임에서도 동적으로 바인딩 시켜줄수있다.
Event는 MultiCastDelegate와 일반적으로 비슷하지만
Event를 선언한 클래스만이 Broadcast, IsBound, Clear 함수를 호출할수있다.
그렇기에 외부 클래스에서 Broadcast, IsBound, Clear 함수를 제한하며 접근권을 확보할때 사용할수있다.
Delegate 선언은 제공되는 매크로중 하나로 이루어진다, 사용되는 매크로는 Delegate와 바인딩되는 함수의 시그니처에따라 결정된다.
다음과 같은 타입들은 Delegate의 시그니처가 지원되는 타입들이다.
- 값을 반환하는 함수
- "페이로드"(payload, 유상) 변수 4 개 까지
- 함수 파라미터 8 개 까지
- 'const' 로 선언된 함수
시그니처 에따른 Delegate매크로들은 다음과 같다.
| 함수 시그너처 | 선언 매크로 |
|---|---|
void Function() | DECLARE_DELEGATE( DelegateName ) |
void Function( <Param1> ) | DECLARE_DELEGATE_OneParam( DelegateName, Param1Type ) |
void Function( <Param1>, <Param2> ) | DECLARE_DELEGATE_TwoParams( DelegateName, Param1Type, Param2Type ) |
void Function( <Param1>, <Param2>, ... ) | DECLARE_DELEGATE_<Num>Params( DelegateName, Param1Type, Param2Type, ... ) |
<RetVal> Function() | DECLARE_DELEGATE_RetVal( RetValType, DelegateName ) |
<RetVal> Function( <Param1> ) | DECLARE_DELEGATE_RetVal_OneParam( RetValType, DelegateName, Param1Type ) |
<RetVal> Function( <Param1>, <Param2> ) | DECLARE_DELEGATE_RetVal_TwoParams( RetValType, DelegateName, Param1Type, Param2Type ) |
<RetVal> Function( <Param1>, <Param2>, ... ) | DECLARE_DELEGATE_RetVal_<Num>Params( RetValType, DelegateName, Param1Type, Param2Type, ... ) |
Delegate선언은 글로벌, 네임스페이스 안, 클래스 선언부(함수본문 제외) 영역에서 선언이가능하다.
MultiCastDelegate또한 표준Delegate선언과 크게 다르지않으며
MultiCastDelegate전용 매크로를 사용한다는 차이점이 있다.
| 설명 | 선언 매크로 |
|---|---|
| 멀티캐스트 델리게이트를 생성합니다. | DECLARE_MULTICAST_DELEGATE[_RetVal, etc.]( DelegateName ) |
| 다이내믹 멀티-캐스트 델리게이트를 생성합니다. | DECLARE_DYNAMIC_MULTICAST_DELEGATE[RetVal, etc.]( DelegateName ) |
DynamicDelegate또한 표준Delegate선언과 크게 다르지않으며
DynamicDelegate전용 매크로를 사용한다는 차이점이 있다.
| 설명 | 선언 매크로 |
|---|---|
| 다이나믹 델리게이트를 생성합니다. | DECLARE_DYNAMIC_DELEGATE[_RetVal, etc.]( DelegateName ) |
| 다이나믹 멀티-캐스트 델리게이트를 생성합니다. | DECLARE_DYNAMIC_MULTICAST_DELEGATE[_RetVal, etc.]( DelegateName ) |
Event또한 표준Delegate선언과 크게 다르지않으며
Event전용 매크로를 사용한다는 차이점이 있다.
| 설명 | 선언 매크로 |
|---|---|
| 이벤트를 생성합니다. | DECLARE_EVENT( OwningType, EventName ) |
| 파라미터가 하나인 이벤트를 생성합니다. | DECLARE_EVENT_OneParam( OwningType, EventName, Param1Type ) |
| 파라미터가 둘인 이벤트를 생성합니다. | DECLARE_EVENT_TwoParams( OwningType, EventName, Param1Type, Param2Type ) |
| 파라미터가 N 개인 이벤트를 생성합니다. | DECLARE_EVENT_<Num>Params( OwningType, EventName, Param1Type, Param2Type, ... ) |
DECLARE_EVENT 매크로의 첫 파라미터는 이 이벤트를 "소유"(own)하게 될 클래스, 즉 Broadcast() 함수를 호출할 수 있는 클래스이다.Delegate 시스템은 특수한기능도 제공한다, UObject나 공유 포인터 클래스를 바인딩 한경우 약한 레퍼런스를 유지할수있다.
이는 Delegate치하에서 오브젝트가 소멸한경우 IsBound() 나 ExecuteIfBound()함수를 처리해준다.
| 설명 | 함수 |
|---|---|
| 기존 델리게이트 오브젝트에 바인딩합니다. | Bind() |
| raw C++ 포인터 글로벌 함수 델리게이트를 바인딩합니다. | BindStatic() |
| 날(raw) C++ 포인터 델리게이트에 바인딩합니다. 날 포인터는 어떠한 종류의 레퍼런스도 사용하지 않아, 만약 오브젝트가 델리게이트 치하에서 삭제된 경우 호출하기가 안전하지 않을 수도 있습니다. Execute() 호출시에는 조심하세요! | BindRaw() |
| 공유 포인터-기반 멤버 함수 델리게이트에 바인딩합니다. 공유 포인터 델리게이트는 오브젝트로의 약한 레퍼런스를 유지합니다. ExecuteIfBound() 로 호출할 수 있습니다. | BindSP() |
| UObject 기반 멤버 함수 델리게이트를 바인딩합니다. UObject 델리게이트는 오브젝트로의 약한 레퍼런스를 유지합니다. ExecuteIfBound() 로 호출할 수 있습니다. | BindUObject() |
| 이 델리게이트 바인딩을 해제합니다. | UnBind() |
MultiCastDelegate는 여러 개의 함수를 바인딩시켜 Delegate가 발동되면 모두 호출되도록 할 수 있다.
그 결과, 의미론적으로 함수 바인딩이 변수같은 식에 더가깝다.
| 설명 | 함수 |
|---|---|
| 이 멀티캐스트 델리게이트의 실행 목록에 함수 델리게이트를 추가합니다. | Add() |
| raw C++ 포인터 글로벌 함수 델리게이트를 추가합니다. | AddStatic() |
| raw C++ 포인터 델리게이트를 추가합니다. raw 포인터는 어떠한 레퍼런스도 사용하지 않기에, 오브젝트가 자신의 델리게이트 하에서 삭제된 경우 호출시 안전하지 않을 수 있습니다. Execute() 호출시 주의하세요! | AddRaw() |
| 공유 포인터 기반 (빠르지만 스레드 안전성은 떨어지는) 멤버 함수 델리게이트를 추가합니다. 공유 포인터 델리게이트는 자신의 오브젝트에 대한 약 레퍼런스를 유지합니다. | AddSP() |
| UObject 기반 멤버 함수 델리게이트를 추가합니다. UObject 델리게이트는 자신의 오브젝트에 대한 약 레퍼런스를 유지합니다. | AddUObject() |
| 이 멀티캐스트 델리게이트의 실행 목록에서 함수를 제거합니다 (퍼포먼스는 O(N) 입니다). 참고로 델리게이트 순서는 유지되지 않을 수 있습니다! | Remove() |
| 지정된 UserObject 에 바인딩된 이 멀티캐스트 델리게이트의 실행 목록에서 모든 함수를 제거합니다. 참고로 델리게이트 순서는 유지되지 않을 수 있습니다! | RemoveAll() |
RemoveAll() 은 제공된 포인터에 바인딩된 모든 등록 Delegate를 제거한다. 오브젝트 포인터에 바인딩되지 않은 raw Delegate는 이 함수로 제거되지 않는다!| 설명 | 헬퍼 ㄹ매크로 |
|---|---|
| 다이내믹 델리게이트에서 BindDynamic() 호출을 위한 헬퍼 매크로입니다. 함수 이름 문자열을 자동 생성합니다. | BindDynamic( UserObject, FuncName ) |
| 다이내믹 멀티-캐스트 델리게이트에서 AddDynamic() 호출을 위한 헬퍼 매크로입니다. 함수 이름 문자열을 자동 생성합니다. | AddDynamic( UserObject, FuncName ) |
| 다이내믹 멀티-캐스트 델리게이트에서 RemoveDynamic() 호출을 위한 헬퍼 매크로입니다. 함수 이름 문자열을 자동 생성합니다. | RemoveDynamic( UserObject, FuncName ) |
Event바인딩은 MultiCastDelegate 바인딩과 같은 방식으로 이루어진다. (3-1 참고)
Delegate를 바인딩할대 페이로드 데이터를 같이 전달해줄수있다.
바인딩 시간에 Delegate가 파라미터를 보관할수있어 유용하게 사용가능하다.
DynamicDelegate를 제외한 다른 모든 델리게이트들은 페이로드 변수기능을 자동으로 제공한다.
MyDelegate.BindRaw( &MyFunction, true, 20 ); // bool과 int32값을 전달
위 코드는 bool 과 int32를 Delegate에게 전달하는 코드이고, 이파라미터는 바인딩된 Delegate가 실행될때 전달된다.
Delegate에 바인딩된 함수는 Excute()함수를 호출하여 실행한다.
Delegate를 실행하기전 반드시 바인딩 되어있는지 확인해야한다.
Delegate를 싱행시키면 일부 인스턴스에서 메모리에 더미데이터를 남길수도있다.IsBound()함수를 사용해 Delegate를 실행해도 안전한지 확인할수 있다.ExecuteIfBound()로 반환값이없는 Delegate를 호출할수있다, 하지만 호출 파라미터는 초기화하지 않을수 있다.
| 설명 | 함수 |
|---|---|
| 델리게이트에 바인딩된 함수를 호출한다. | Execute() |
| 반환값이 없는 델리게이트를 호출한다. | ExecuteIfBound() |
| 호출할 함수가 델리게이트에 존재하는지 확인한다. | IsBound() |
MultiCastDelegate를 통해 여러함수 Delegate를 붙인다음, MultiCastDelegate의 Broadcast()함수를 통해 함수들을 호출할수 있다.
MultiCastDelegate의 Broadcast()함수는 아무것도 바인딩되어있지 않아도 언제나 안전하다.
하지만 Delegate를 이용해 출력변수를 초기화하는건 매우 좋지않은 일이다.
Broadcast()통해 호출된 함수들의 순서는 정의되지않으며, 함수가 추가된순서대로 실행되지 않을수있다.
| 설명 | 함수 |
|---|---|
| 모든 오브젝트로 호출을 시도한다. | Broadcast() |
DynamicDelegate실행은 Delegate 실행과 같은 방식으로 이루어진다. (5. 참고)
Enevt실행은 MultiCastDelegate실행과 같은 방식으로 이루어진다. (5-1. 참고)
언리얼 공식 홈페이지
언리얼에서 제공하는 Delegate들에대해 알아보았습니다.
번역이나 바로이해가가지않는 부분은 제나름대로 해석하여 수정해보았습니다
공부를 위해 기술하는만큼 잘못된부분이있다면 댓글로 남겨주시기바랍니다!