환경
- macOS Mojave v10.14.6
- Unity 2019.2.5f1
- Github Desktop
- Rider 2019.2
- UniRx v7.1.0
원문 : https://qiita.com/toRisouP/items/35b4d6255c1f9ecf27d1
이 포스팅은 원문을 단순히 구글 번역을 하여 정리한 내용입니다. 일본어를 잘하시는 분은 원문을 보시는게 더 좋으실 것 같습니다.
UniRx에 대한 기사 요약은 여기
Subscribe 및 Dispose
Rx에서는 Observable를 구독하고 메시지를 대기하는 것을 Subscribe라고 부르고, 그 구독을 중지하는 것을 Disponse라고 부릅니다.
이 Subscribe는 조심해야 되는 부분이 있습니다. Observable이 파괴된 타이밍에 제대로 Dispose 할 필요가 있습니다.
Observable이 파괴될 때에 OnCompleted가 발행되면 자동으로 Dispose가 됩니다만, 스트림에 따라서는 OnCompleted가 발행되지 않는 경우도 있습니다.
Observable의 수명을 고려하지 않고 사용한 경우
우선 다음 코드와 실행 결과를 봅시다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using UniRx;
using UnityEngine;
public class ObservableLifeTime : MonoBehaviour
{
private void Start()
{
// 1 초마다 메시지를 발행하는 Observable
Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1))
.Subscribe(x => Debug.Log(x));
// 3 초 후에 GameObject를 제거한다
Invoke("DestroyGameObject", 3);
}
/// <summary>
/// 로그를 출력하고 오브젝트를 제거한다.
/// </summary>
private void DestroyGameObject()
{
Debug.Log("Destroy");
Destroy(gameObject);
}
}
실행 결과
Destroy에서 GameObject가 파괴 된 후에도, Observable.Timer로 만든 스트림은 계속 실행되고 있습니다.
이것은 Observable.Timer로 만든 Observable가 static으로 생성되어 버려, GameObject에 관계없이 독립적으로 작동하기 때문 입니다.
AddTo로 Subscribe와 GameObject를 연결한다.
AddTo를 사용하면 이 문제를 쉽게 해결할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using UniRx;
using UnityEngine;
public class ObservableLifeTime : MonoBehaviour
{
private void Start()
{
// 1 초마다 메시지를 발행하는 Observable
Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1))
.Subscribe(x => Debug.Log(x))
.AddTo(gameObject); // GameObject의 수명과 연결.
// 3 초 후에 GameObject를 제거한다
Invoke("DestroyGameObject", 3);
}
/// <summary>
/// 로그를 출력하고 오브젝트를 제거한다.
/// </summary>
private void DestroyGameObject()
{
Debug.Log("Destroy");
Destroy(gameObject);
}
}
실행 결과
AddTo를 사용하는 것으로, Subscribe의 Dispose를 지정한 GameObject의 수명에 연결시켜, GameObject가 Destroy시에 자동으로 Dispose 해주게 되었습니다.
이제 Dispose 관리를 신경 쓰지 않고 팩토리 메소드를 사용할 수 있게 되었습니다! (UniRx 내부적으로 Timer의 경우 new TimeObservable 형태의 팩토리 메서드 패턴 형태로 구현되어 있습니다)
다만, OnCompleted가 실행되는 것은 아니기 때문에 그 점은 조심하시기 바랍니다.