LoginSignup
11
10

More than 5 years have passed since last update.

UnityでParseを使う時に陥りがちなワナ

Last updated at Posted at 2015-11-06

皆さんParse使ってます?
こちらの記事でも書きましたが、秒間30リクエストまで無料というゲーム開発者を幸せにしてくれる脅威のmBaaSです。

で、Parseで検索してみると結構サンプルが出てくるんですよね。
見てみると、みなさま大抵はレスポンスの受け取りにContinueWith()を使ってらっしゃる。
公式のDocsにも書いてあるので当然です。

ただ、実はContinueWith()を使うとハマります。
今回はそこらへんに関してちょこっとノウハウを書いてみようと思います。

何が問題なのか?

んでは、ParseのHogeテーブルから全件取得するクエリを書いてみましょう。
※↓は正常系のみ書いてます。組み込む際はエラーハンドリングの処理も書きましょー

    public void ParseRequestTest()
    {
        var query = new ParseQuery<ParseObject>("Hoge");
        query.FindAsync().ContinueWith(t => {
            var objectIds = new List<string>();

            // FindAsync()だとt.ResultにはIEnumerable<ParseObject>が入っている
            foreach (var parseObject in t.Result) {
                // とりあえずobjectIdでも集めてみようかな
                objectIds.Add(parseObject.ObjectId);
            }

            // uGUIのTextに表示してみようかな
            GameObject.Find("ObjectIds").GetComponent<Text>().text = objectIds.ToString();

            // ついでにPlayerPrefsにも放り込んでみようかな
            PlayerPrefs.SetString("objectIds", objectIds.ToString());
            PlayerPrefs.Save();
        });
    }

至って普通のコードに見えますが、実行するとコケます。

理由はカンタン。
ContinueWith()のコールバックは別スレッドで実行されるので、UnityのAPIが使えないのです。
GameObjectもいじれませんし、PlayerPrefsへの書き込みもできません。

じゃあどうすればいいの?

答えは単純で、ContinueWith()を使わなければOK。
実際にContinueWith()を使わないメソッドを作ってみましょー。

    public void ParseRequestTest()
    {
        StartCoroutine(ParseRequestTestCoroutine());
    }

    private IEnumerator ParseRequestTestCoroutine()
    {
        var query = new ParseQuery<ParseObject>("Hoge");

        // ContinueWith()のコールバックで得られるリクエストスレッドオブジェクトは○○Async()の戻り値でも得られるのでコレを利用
        var t = query.FindAsync();
        yield return new WaitUntil( () => t.IsCompleted );// リクエストが終わるまで待つ

        var objectIds = new List<string>();
        // FindAsync()だとt.ResultにはIEnumerable<ParseObject>が入っている
        foreach (var parseObject in t.Result) {
            // とりあえずobjectIdでも集めてみようかな
            objectIds.Add(parseObject.ObjectId);
        }

        // uGUIのTextに表示してみようかな
        GameObject.Find("ObjectIds").GetComponent<Text>().text = objectIds.ToString();

        // ついでにPlayerPrefsにも放り込んでみようかな
        PlayerPrefs.SetString("objectIds", objectIds.ToString());
        PlayerPrefs.Save();
    }

Parseのタスクオブジェクトは、ContinueWith()のコールバックだけではなく○○Async()メソッドの戻り値としても受け取れるので、こいつのIsCompletedを監視すればOK。
ちとコードが長くはなりますが、一般的なコルーチンとして扱えるのでベンリです。


2016/6/1追記: Unity5.3から登場したWaitUntilを使ったパターンの編集リクエストをいただきましたので、反映しました。
taskがIsCompletedになるのを待っていた部分で、whileの代わりに使用しています。
情報ありがとうございます!

11
10
0

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
11
10