Unity
Parse
mBaas

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

More than 1 year has passed since last update.

皆さん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の代わりに使用しています。

情報ありがとうございます!