LoginSignup
15
9

More than 5 years have passed since last update.

Unity NCMBをUniRxで扱えるようにしてみた

Last updated at Posted at 2017-04-18

はじめに

ニフティクラウド mobile backend(以降NCMB)とは、ニフティさんが提供するmBaaSサービスです。
クラウドサーバ上に会員登録やデータの保存や検索ができるサービスです。

NCMB

Unity Plugin

このNCMBはUnity向けのPlguinを提供しており、無料で利用することができるようになっています。

https://github.com/NIFTYCloud-mbaas/ncmb_unity

NCMB Unity Pluginの問題点

さて、このUnity Pluginなのですが「APIの非同期実行時にコールバックがネストする」という問題点があります。

ネストする例
//ログインして成功したらユーザの詳細情報を取得する
NCMBUser.LogInAsync("test_user_id", "test_password", error =>
{
    if (error != null)
    {
        //失敗
        Debug.LogError(error);
    }
    {
        //ログインに成功したらユーザの詳細取得
        var currentUser = NCMBUser.CurrentUser;
        currentUser.FetchAsync(exception =>
        {
            if (exception != null)
            {
                //失敗
                Debug.LogError(exception);
            }
            else
            {
                //成功
                //ユーザの登録されたメールアドレスの表示
                Debug.Log(currentUser.Email);
            }
        });
    }
});

解決してみた

こういう非同期処理のコールバックのネストを解消するデザインパターンとして古くからFuture/Promiseパターンが利用されています。今回はこのデザインパターンと互換性のあるUniRxのIObservableに置き換えることで、このコールバックのネスト問題を解消してみました。

NcmbAsObservable

というわけで、NCMB Unity PluginをUniRxで触れる用にするライブラリを作ってみました。

NcmbAsObservableからダウンロードしてください。
(いいライブラリ名が思いつかなかったので適当です)

使い方

using NcmbAsObservables; をまず追加してください。それでいろいろ呼び出せるようになります。

例1: ログインしてデータ取得

NCMBUserにstaticで生えているAPIメソッドはObservableFromNcmbUserから呼び出すことができます。

ログインしてデータ取得
ObservableFromNcmbUser
    .LogInAsync("test_user_name", "hogehoge") //Login
    .SelectMany(u => u.FetchAsyncAsStream())  //Fetch
    .Subscribe(u => Debug.Log(u.Email), e => Debug.LogError(e));

このようにIObservable化してしまえばコールバックのネストが消えてフラットにコードを書くことが出来るようになります。

例2:サインインしてユーザ情報を書き換える

NCMBが用意したオブジェクトに生えている~Async系のAPIは末尾をAsyncAsStreamと呼び替えることでIObservable版を呼び出すことができるようになります。
(本当は ~AsyncAsObservable にしたかったんだけど、長さ1のストリームをObservableと呼ぶのに抵抗があったためこんな変な名前になりました。他に良い命名があればプルリクお願いします。)

サインインしてユーザ情報を書き換える

var user = new NCMBUser();

user.UserName = "test_user_name";
user.Password = "hogehoge";

//サインイン→成功したらデータ書き換え→再取得→結果表示

//Signup
user.SignUpAsyncAsStream()
.SelectMany(u =>
{
    //Change email and Age column when signed up
    u.Email = "test@test.com";
    u["Age"] = 20;
    return u.SaveAsyncAsStream(); //Save
})
.SelectMany(u => u.FetchAsyncAsStream()) //Fetch
.Subscribe(u =>
{
    Debug.Log(string.Format("{0}\t{1}\t{2}", u.UserName, u.Email, u["Age"]));
}, e =>
{
    Debug.LogError(" Error:" + e);
});

このように、AsyncAsStreamに書き換えることでIObservable化することができます。
また、途中で発生したエラーはOnErrorを流れるのでこんな感じでエラーハンドリングもできます。

例外が発生したポイントでログを出す
var user = new NCMBUser();

user.UserName = "test_user_name";
user.Password = "hogehoge";

//サインイン→成功したらデータ書き換え→再取得→結果表示

//Signup
user.SignUpAsyncAsStream()
.Catch((NCMBException e) =>
{
    Debug.LogError("Error on sign up:" + e);
    return Observable.Empty<NCMBUser>();
})
.SelectMany(u =>
{
    //Change email and Age column when signed up
    u.Email = "test@test.com";
    u["Age"] = 20;
    return u.SaveAsyncAsStream(); //Save
})
.Catch((NCMBException e) =>
{
    Debug.LogError("Error on save:" + e);
    return Observable.Empty<NCMBUser>();
})
.SelectMany(u => u.FetchAsyncAsStream()) //Fetch
.Catch((NCMBException e) =>
{
    Debug.LogError("Error on Fetch:" + e);
    return Observable.Empty<NCMBUser>();
})
.Subscribe(u =>
{
    Debug.Log(string.Format("{0}\t{1}\t{2}", u.UserName, u.Email, u["Age"]));
}, e =>
{
    Debug.LogError("Unknown Error:" + e);
});

例3: NCMBQueryを使う

NCMBQueryはNCMBのデータストアに対してクエリを発行してオブジェクトを検索する時に使うオブジェクトです。
このNCMBQueryは対応する型をジェネリックで渡さないといけない関係で拡張メソッド化ができませんでした。
なので代わりに NCMBQueryHelper<T>を用意したのでこちらを経由してAPIを実行すればIObservable化できるようになっています。

NCMBQueryも同様に拡張メソッド経由でObservableとして扱えるようになっています。

NCMBQueryHelper
var query = new NCMBQuery<NCMBObject>("Score");
query.OrderByDescending("score");
query.Limit = 5;

query
    .FindAsyncAsStream()
    .Subscribe(resultList =>
    {
        foreach (var o in resultList)
        {
            Debug.Log(o);
        }
    }, error => Debug.LogError(error));

最後に

触れる頻度の高いNCMBUserを中心にIObservable化しています。
まだコールバックをとる非同期APIのIObservable化に漏れがあるかもしれませんので、見つけた時は報告いただけるかプルリクをくれるとありがたいです。

15
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
9