UniRxのシンプルなサンプル その6(購読の停止)

[UniRxのシンプルなサンプルの取扱説明書](http://qiita.com/Marimoiro/items/b0c66c6c22cf58bde049)
[前(Buttonが押されたら動くGameObjet)](http://qiita.com/Marimoiro/items/bba05b7b1e15f0c804a8)
[次(完了の通知)]
(http://qiita.com/Marimoiro/items/31cad556e1675c557be3)

#購読の停止#

以下のコードを見てください

```csharp:DeadUpdate
using UnityEngine;
using System.Collections;
using UniRx;
using System;

public class DeadUpdate : Base {

	// Use this for initialization
	void Start () {
        
        gameObject.transform.position = new Vector2(0, 1f);

        //5秒後にgameObjectが死ぬ
        Observable.Timer(TimeSpan.FromSeconds(5))
           .Subscribe(_ => Destroy(gameObject));

        //0.5秒ごとに0.05右に移動
        Observable.Interval(TimeSpan.FromMilliseconds(500))
            .Subscribe(l => Move(0.5f, 0));
	}

	private void Move(float x, float y)
	{
		gameObject.transform.position = new Vector2(
			gameObject.transform.position.x + x, 
			gameObject.transform.position.y + y
		);
	}
}

```
このコードは5秒後に`gameObject`が破棄されるまで0.5秒毎にカクカクと右に動き続けることを想定したコードです。

しかし、このコードは5秒後に`gameObject`の破棄と同時に例外を吐いてしまいます。

`Observable.Interval(TimeSpan time)`は`time`ごとに値をプッシュし続ける登録先です。
`Observable.Timer(TimeSpan time)`は`time`の後に1回だけ値をプッシュしてくれる登録先です。
それぞれ詳しくは[UniRxのシンプルなサンプル その9(TimerとInterval 一定時間後に実行)](http://qiita.com/Marimoiro/items/a72b60315c797c19a27c)を参照してください。

こんなかんじです。
![スクリーンショット 2015-05-03 18.05.08.png](https://qiita-image-store.s3.amazonaws.com/0/77177/3bc62ad3-943b-fe00-8f73-7f8f00980e4b.png)


これの何が悪いかというと`Observable.Interval(TimeSpan.FromMilliseconds(500)).Subscribe(l => Move(0.5f, 0));`で行った登録がgameObjectが破棄された後も生き残っていて`Move`を呼びだしちゃってるんですよね。
これは`Subscribe`で行った登録の登録解除(購読の停止とかいいます)をちゃんとしなければいけないよということです。
なので、この問題の解消をします。

## 準備 ##
かなりシンプルに1個だけ`SafeUpdate`というものをくっつけて作ります。
![スクリーンショット 2015-05-03 17.38.13.png](https://qiita-image-store.s3.amazonaws.com/0/77177/d3729aa0-0bdd-cbb2-16a0-9f7fe5aa5d4d.png)

## AddTo ##
一番簡単な方法は以下のコードになります。

```csharp:SafeAddTo
using UnityEngine;
using System.Collections;
using UniRx;
using System;

public class SafeUpdate : Base
{

	// Use this for initialization
	void Start () {
        
        gameObject.transform.position = new Vector2(0, 1f);

        //5秒後にgameObjectが死ぬ
        Observable.Timer(TimeSpan.FromSeconds(5))
            .Subscribe(_ => Destroy(gameObject));

        //0.5秒ごとに0.05右に移動
        Observable.Interval(TimeSpan.FromMilliseconds(500))
            .Subscribe(l => Move(0.1f, 0))
            .AddTo(this);//これを消すと登録が解除できず例外
	}
}

```
このように`Subscribe`の後に`.AddTo(Component c);`で`c`が破棄されたら一緒に購読停止してくれます。
これが一番簡単な方法ですね。

## TakeUntilDestroy ##
更に`TakeUnitilDestroy`とか`TakeUntilDisable`とかもあります。

```csharp:SafeUpdate
using UnityEngine;
using System.Collections;
using UniRx;
using System;

public class SafeUpdate : Base
{

	// Use this for initialization
	void Start () {
        
        gameObject.transform.position = new Vector2(0, 1f);

        //5秒後にgameObjectが死ぬ
        Observable.Timer(TimeSpan.FromSeconds(5))
            .Subscribe(_ => Destroy(gameObject));

        //0.5秒ごとに0.05右に移動
        Observable.Interval(TimeSpan.FromMilliseconds(500))
            .TakeUntilDestroy(this)//これを消すと例外
            .Subscribe(l => Move(0.1f, 0));
	}
}
```
`TakeUntilDestroy(this)`はt`his`が破棄されたらプッシュをやめます。

ちなみにですが後で説明する予定ですが、`AddTo`では`Dispose()`されるだけなのに対し、`TakeUntilDestroy`等では`OnCompleted`というプッシュの終了が通知されることになるという違いがあります。

## 購読の停止(手動) ##
実は`Subscribe`の戻り値は`IDisposable`です。
これを`Dispose`すると購読が停止されます。

なので手動での削除はこんなコードになります。

```csharp:SafeUpdate
using UnityEngine;
using System.Collections;
using UniRx;
using System;

public class SafeUpdate : Base
{

	// Use this for initialization
	void Start () {
        
        gameObject.transform.position = new Vector2(0, 1f);

        IDisposable mover =　 Observable.Interval(TimeSpan.FromMilliseconds(500))
            .TakeUntilDestroy(this)
            .Subscribe(l => Move(0.1f, 0));

        //5秒後にgameObjectが死ぬ
        Observable.Timer(TimeSpan.FromSeconds(5)).Subscribe(_ => 
        {
            mover.Dispose();//moverを破棄して購読停止
            Destroy(gameObject);
        });
	}
}


```


削除されることが想定されているような`gameObject`を扱うときは登録先とか自分自身の寿命を考えるといいと思います。
ていうか基本`AddTo`するといいと思います。

今までのサンプルの`this.UpdateAsObservable()`は`this`自身がオブザーバーだったので削除されても問題なく正常にストップします。

## 実行結果 ##
ちゃんと消えたのにエラー出ませんやったー！
![スクリーンショット 2015-05-03 17.48.18.png](https://qiita-image-store.s3.amazonaws.com/0/77177/d181600c-63d2-ba6b-3e6f-621d0b8186c8.png)