なんだかんだでプログラムが好き

私 すずきかつーき が主にプログラムに関する事を書いたり書かなかったりします

YieldableNcmbQuery

なんとNCMBのUnityPluginがWebGLビルド対応したそうです。(未テスト)

github.com

ところで、このNCMBの検索処理(NCMBQueryのFindAsync)って、Asyncと付いてるだけあって非同期だと思うんですけど、コールバックでResultとError(Errorじゃなければnull)が格納される仕組みになってるんですよ。

でも、コールバックってネストが深くなって辛いですよね

Unityでコールバック形式の処理をコルーチンを使ってさも手続き処理風にやりたい場合

これを

       var query = new NCMBQuery<NCMBObject>("Ranking");
        query.FindAsync((_result, _error) =>
        {
            //後続処理 
            if (_error == null)
            {
                foreach (var data in _result)
                {
                    Debug.Log(data);
                }
            }
        });
        Debug.Log("Finis....h????"); //ここはすぐ処理されちゃう

こんな感じで

   void Start ()
    {
        StartCoroutine(ScoreLoadIterator());
    }

    private IEnumerator ScoreLoadIterator()
    {
        var query = new NCMBQuery<NCMBObject>("Ranking");
        List<NCMBObject> result = null;
        NCMBException error = null;
        query.FindAsync((_result, _error) =>
        {
            result = _result;
            error = _error;
        });
    
        //resultもしくはerrorが入るまで待機
        yield return new WaitWhile(() => result == null && error == null);
    
        //後続処理 
        if (error == null)
        {
            foreach (var data in result)
            {
                Debug.Log(data);
            }
        }
        Debug.Log("Finish!!!");
    }

やったりしますが、これはこれで、resultとerror格納用の変数を用意しなきゃいけないし、null初期化しておく必要もあってvarで変数宣言も出来ないので嫌な感じ。

もう継承してそういうクラス作っちゃおう

public class YieldableNcmbQuery<T> : NCMBQuery<T> where T:NCMBObject
{
    public List<T> Result { private set; get; }
    public NCMBException Error { private set; get; }

    public CustomYieldInstruction FindAsync()
    {
        Result = null;
        Error = null;
        FindAsync((objects, error) =>
        {
            Result = objects;
            Error = error;
        });     
        return new WaitWhile(() => Result == null && Error == null);
    }

    public YieldableNcmbQuery(string theClassName) : base(theClassName)
    {
    }
}

こんな感じで薄く拡張したサブクラスを作っておくと

   void Start ()
    {
        StartCoroutine(ScoreLoadIterator());
    }

    private IEnumerator ScoreLoadIterator()
    {
        var query = new YieldableNcmbQuery<NCMBObject>("Ranking");
        yield return query.FindAsync();
    
        //後続処理 
        if (query.Error == null)
        {
            foreach (var data in query.Result)
            {
                Debug.Log(data);
            }
        }
        Debug.Log("Finish!!!");
    }

非常にすっきりします。 やったね。