After updating today to Xamarin iOS 6.4 our project now encounters a fatal startup error to do with generics which did not occur previously. This has completely halted our development.
Relevant stack section InnerException was ExecutionEngineException: Attempting to JIT compile method 'ourapp.TouchTaskFactory:StartNew (System.Func`1)' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.
The code declaration causing the issue is below - it was being used to provide a wrapper to parallel tasks library between our PCL core library and the Monotouch front-end project.
The PCL project is using Visual Studio PCL Profile104/.net 4.0. We attempted to update it to Profile 78/.net 4.5 however this causes problems for the front-end Monotouch project - it complains we need to add references to System.Runtime v4.0, which even if done via Profile 78's ReferenceAssemblies causes failure when building on the Mac.
Could you please advise as a matter of urgency the best path to work around this issue. Ideally we would like to dump our parallel tasks wrapper and move to async/await, but any temporary workaround would be appreciated.
Code causing the issue:
From the PCL
/// <summary>
/// Cross platform wrapper for parallel tasks until Xamarin release async PCL support
/// </summary>
public interface ITaskFactory
{
ITask<TResult> StartNew<TResult>(Func<TResult> function);
}
/// <summary>
/// Cross platform wrapper for parallel tasks until Xamarin release async PCL support
/// </summary>
public interface ITask<TResult> : IDisposable, IAsyncResult
{
bool IsCanceled { get; }
bool IsFaulted { get; }
TResult Result { get; }
Exception Exception { get; }
ITask<TResult> ContinueWith(Action<ITask<TResult>> continuationAction);
}
/// <summary>
/// Cross platform wrapper for parallel tasks until Xamarin release async PCL support.
///
/// Initalize on startup by platform-specific code
/// </summary>
public class TaskFactory
{
public static ITaskFactory Factory { get; set; }
}
From the Monotouch app
During app startup (mvvmcross type registration in our case):
ThePCLLibrary.TaskFactory.Factory = TouchTaskFactory.Instance;
public class TouchTaskFactory : ITaskFactory { private static TouchTaskFactory _instance;
protected TouchTaskFactory()
{
}
public static TouchTaskFactory Instance
{
get { return _instance ?? (_instance = new TouchTaskFactory()); }
}
public ITask<TResult> StartNew<TResult>(Func<TResult> function)
{
var nativeTask = Task.Factory.StartNew(function);
var wrapped = new TouchTask<TResult>(nativeTask);
return wrapped;
}
}
public class TouchTask : ITask, IDisposable, IAsyncResult { private readonly Task _nativeTask;
public TouchTask(Task<TResult> nativeTask)
{
_nativeTask = nativeTask;
}
public Exception Exception
{
get { return _nativeTask.Exception; }
}
public bool IsCanceled
{
get { return _nativeTask.IsCanceled; }
}
public object AsyncState
{
get { return _nativeTask.AsyncState; }
}
public WaitHandle AsyncWaitHandle
{
get { return ((IAsyncResult) _nativeTask).AsyncWaitHandle; }
}
public bool CompletedSynchronously
{
get { return ((IAsyncResult) _nativeTask).CompletedSynchronously; }
}
public bool IsCompleted
{
get { return _nativeTask.IsCompleted; }
}
public bool IsFaulted
{
get { return _nativeTask.IsFaulted; }
}
public TResult Result
{
get { return _nativeTask.Result; }
}
public ITask<TResult> ContinueWith(Action<ITask<TResult>> continuationAction)
{
_nativeTask.ContinueWith(task => continuationAction(this));
return this;
}
public void Dispose()
{
if (_nativeTask != null)
_nativeTask.Dispose();
}
}
Finally, usage in the PCL
private void SomeMethod(){
TaskFactory.Factory.StartNew(() => { // code...
return true;
}).ContinueWith(task =>
{
// stuff with result
});
}
Thanks,