IL2CPPでLINQのAOTエラーが結構改善されたような気がする
という話
以下の記事の通りかわいいかわいいLINQちゃんはiOSだと気をつけて使わないとクラッシュする。
と言う問題がMonoの時にはありました。
Unity + iOSのAOTでの例外の発生パターンと対処法とか
Unity+iOSでエラーになるLINQのまとめ - Qiita
どうやらIL2CPPになった段階で結構解消されたような気がするので、テストコード書いてみてクラッシュするかなー?しないかなー?って確認したところ以下のメソッドは全部AOTでクラッシュしませんでした。(手元の環境はXcode7,iOS9,Unity5.3.2p3で確認)
Unity+iOSでエラーになるLINQのまとめ - Qiita
を参考に以下のクラッシュしていたメソッドのみ検証です。
- Average
- Max
- Min
- Sum
- FirstOrDefault
- Last
- LastOrDefault
- Single
- SingleOrDefault
- ToDictionary
- ToLookup
- Join
- OrderBy
- OrderByDescending
クラッシュ本当にしないのかは検証不足なのですが、なんかいい感じに解決してそうなので公開しておきます。(だれか追試してー)
using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
public struct SimpleStruct{
public int Value{get;set;}
public SimpleStruct(int value):this(){
Value = value;
}
}
public class SimpleClass{
public int Value{get;set;}
public SimpleClass(int value){
Value = value;
}
}
public class AOTTest : MonoBehaviour {
void OnGUI()
{
if(GUILayout.Button("Test Average"))
{
var ave = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).Select(s => s.Value).Average();
Debug.Log("Average:" + ave);
}
if(GUILayout.Button("Test Max"))
{
var max = new int[10].Select(_=>new SimpleClass(Random.Range(0,1000))).Select(s => s.Value).Max();
Debug.Log("Max:" + max);
}
if(GUILayout.Button("Test Min"))
{
var min = new int[10].Select(_=>new SimpleClass(Random.Range(0,1000))).Select(s => s.Value).Min();
Debug.Log("Min:" + min);
}
if(GUILayout.Button("Test Sum"))
{
var sum = new int[10].Select(_=>new SimpleClass(Random.Range(0,1000))).Select(s => s.Value).Sum();
Debug.Log("Sum:" + sum);
}
if(GUILayout.Button("Test FirstOrDefault"))
{
var first = new int[10].Select(_=>Random.Range(0,1000)).FirstOrDefault();
Debug.Log("First:" + first);
}
if(GUILayout.Button("Test Last"))
{
var last = new int[10].Select(_=>Random.Range(0,1000)).Last();
Debug.Log("Last:" + last);
}
if(GUILayout.Button("Test LastOrDefault"))
{
var last = new int[10].Select(_=>Random.Range(0,1000)).LastOrDefault();
Debug.Log("LastOrDefault:" + last);
}
if(GUILayout.Button("Test Single"))
{
var value = new int[10].Select((i,n)=>n).Take(1).Single();
Debug.Log("Single:" + value);
}
if(GUILayout.Button("Test SingleOrDefault"))
{
var value = new bool[10].Select((i,n)=>n).Take(1).SingleOrDefault();
Debug.Log("SingleOrDefault:" + value);
}
if(GUILayout.Button("Test Join"))
{
var a = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToArray();
var dic = a.Join(a,i=>i.Value,o => o.Value,(i,o)=> i.Value + o.Value).ToArray();
Debug.Log (dic);
}
if(GUILayout.Button("Test ToDictionary 1"))
{
var dic = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToDictionary (skill => skill.Value);
DictionaryLog(dic);
}
if(GUILayout.Button("Test ToDictionary 2"))
{
var dic = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToDictionary (skill => skill.Value,EqualityComparer<int>.Default);
DictionaryLog(dic);
}
if(GUILayout.Button("Test ToLookup 1"))
{
var dic = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToLookup (skill => skill.Value);
LookupLog(dic);
}
if(GUILayout.Button("Test ToLookup 2"))
{
var dic = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).ToLookup (skill => skill.Value,EqualityComparer<int>.Default);
LookupLog(dic);
}
if(GUILayout.Button("Test OrderBy")){
var a = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).OrderBy( k => k.Value);
foreach (var item in a) {
Debug.Log("Sort"+item.Value);
}
}
if(GUILayout.Button("Test OrderByDescending")){
var a = new int[10].Select(_=>new SimpleStruct(Random.Range(0,1000))).OrderByDescending( k => k.Value);
foreach (var item in a) {
Debug.Log("Sort"+item.Value);
}
}
}
private void DictionaryLog<K,T>(Dictionary<K,T> dict)
{
foreach(var kv in dict)
{
Debug.Log(kv.Key + ":" + kv.Value);
}
}
private void LookupLog<K,T>(ILookup<K,T> dict)
{
foreach(var kv in dict)
{
Debug.Log(kv.Key + ":" + kv.ToArray());
}
}
}
こういう書捨てのコード書くときレガシーGUI便利だと思います。
やってないこと
- 他のメソッドが死んでないかのテスト
- 他のバージョンでのテスト