Assign delegate crashes only on iOS

hey, i met really weird situation that my codes crashes only on iOS run.
i couldn’t solve it! it makes me mad. here’s my codes:

using System.Collections.Generic;

[System.Serializable]
public class ExclusiveFSM<T> : System.Object 
{	
	// Public Member Variables
	//-----------------------------------------------------------------------    
	public delegate void ParamEventDelegate(ExclusiveFSM<T> fsm, object param);
	public delegate void EventDelegate(ExclusiveFSM<T> fsm);

	public event ParamEventDelegate OnStateBegin = delegate { };
	public event EventDelegate OnStateUpdate = delegate { };
	public event EventDelegate OnStateEnd = delegate { };
	
	// Hidden Member Variables
	//-----------------------------------------------------------------------
	protected class StateQueueEntry
	{
		public float delay;
		public T state;
		public object param;

		public StateQueueEntry(float delay, T state, object param)
		{
			this.delay = delay;
			this.state = state;
			this.param = param;
		}
	}

	protected Queue<StateQueueEntry> stateQueue = new Queue<StateQueueEntry>();

	protected T currentState;
	protected T previousState;

	protected float currentStateTime = 0.0f;

	// Public Methods
	//-----------------------------------------------------------------------
	public void Update(float deltaTime)
	{
		currentStateTime += deltaTime;
		OnStateUpdate(this);
		ProcessStateQueue();
	}

	public void Play(T newState, object param)
	{
		stateQueue.Clear();
		TransitState(newState, param, 0.0f);
	}

	public void Play(T newState)
	{
		Play(newState, null);
	}

	public void Blend(T newState, object param)
	{
		if (!currentState.Equals(newState))
		{
			stateQueue.Clear();
			TransitState(newState, param, 0.0f);
		}
	}

	public void Blend(T newState)
	{
		Blend(newState, null);
	}

	public void Queue(float delay, T newState, object param)
	{
		stateQueue.Enqueue(new StateQueueEntry(delay, newState, param));
	}

	public void Queue(float delay, T newState)
	{
		Queue(delay, newState, null);
	}

	public T CurrentState
	{
		get { return currentState; }
	}

	public T PreviousState
	{
		get { return previousState; }
	}

	public float CurrentStateTime
	{
		get { return currentStateTime; }
		set { currentStateTime = value; }
	}

	// Hidden Methods
	//-----------------------------------------------------------------------
	protected void TransitState(T newState, object param, float initialStateTime)
	{		
		OnStateEnd(this);

		previousState = currentState;
		currentState = newState;
		currentStateTime = initialStateTime;

		OnStateBegin(this, param);
	}

	protected void ProcessStateQueue()
	{
		if (stateQueue.Count == 0)
			return;

		StateQueueEntry entry = stateQueue.Peek();

		float deltaTime = currentStateTime - entry.delay;

		if (deltaTime > 0.0f)
		{
			stateQueue.Dequeue();
			TransitState(entry.state, entry.param, deltaTime);
		}
	}
}

below is one which uses it.

using UnityEngine;

public class TestDelegateCrash : MonoBehaviour
{
	public enum State
	{
		Dumb,
		Dumber,
		Dumbest
	}
	
	ExclusiveFSM<State> fsm = new ExclusiveFSM<State> ();
	
	void Awake ()
	{
		fsm.OnStateBegin += OnStateBegin;
		fsm.OnStateUpdate += OnStateUpdate;
		fsm.Play (State.Dumb);
	}
	
	void Update ()
	{
		fsm.Update (Time.deltaTime);
	}

	protected virtual void OnStateBegin (ExclusiveFSM<State> fsm, object param)
	{
		Debug.Log ("Dumb");
	}
	
	protected virtual void OnStateUpdate (ExclusiveFSM<State> fsm)
	{
		Debug.Log ("Dumbing");
	}
}

when i run this behavior on editor, it works perfectly. but if i deploy on iOS it crashes all time!
call stack says it crashed on line of code:

fsm.OnStateBegin += OnStateBegin;

any ideas? i deadlocked on this issue :frowning:

hmmm… i’d better convert this code to using event handler pattern rather than delegate-event pattern :frowning:

Hi,
which Unity version are you using? Unity 3.5 fixes some bug, which might affect your case.

Mono’s AOT compiler is not going to like: public delegate void EventDelegate(ExclusiveFSM fsm);
Since iOS runs in ahead of time mode(AOT), it can’t generate code at runtime. What the AOT compiler does for generics is look at your code and determine which variations of each generic are required, normally something that can be done by the JIT at runtime. But when nesting generics, or having generic function parameters that are not explicitly types in code somewhere, it can get thrown off. In this case it would be extremely difficult for the compiler to deduce exactly which versions of the ParamEventDelegate to create because there is nothing restricting the type T in the parameter to the type T in the instance of fsm containing OnStateBegin, and therefore no explicit in code definition of ParamEventDelegate taking an ExclusiveFSM.

I know MonoTouch had an attribute that could help with some delegate issues involving Callbacks, and I’m curious if 3.5 has any new tools for complex generics, seeing what Mantasp replies with.

i’m using unity 3.5 release version and it still doesn’t work :frowning:

thank you for advice! it sounds like this problem is very similar to template problem in c++. i think you are right. so you mean i have to explicitly define some generic classes or functions rather than ambiguous T type? ok i’d like to test it right now, then i’ll report how it works as soon as possible. thank you again :slight_smile:

I tried some codes for resolving generic-delegate problem above.

First, I replaced parameter ‘ExclusiveFSM’ to ‘State’ in handler methods,

    protected virtual void OnStateBegin (State currentState, object param)
    {
        Debug.Log ("Dumb");
    }

    protected virtual void OnStateUpdate (State currentState)
    {
        Debug.Log ("Dumbing");
    }

FAILED. i tried another one, which limits T type as enum = struct, IConvertible

using System.Collections.Generic;

[System.Serializable]
public class ExclusiveFSM<T> where T : struct, System.IConvertible : System.Object
{  
     ....
}

yet FAILED. i thought the delegate definition in generic class totally malfunctioning, so i abandoned generic implementions,

using System.Collections.Generic;

[System.Serializable]
public class ExclusiveFSM : System.Object
{   
    // Public Member Variables
    //-----------------------------------------------------------------------    
    public delegate void ParamEventDelegate(ExclusiveFSM fsm, object param);
    public delegate void EventDelegate(ExclusiveFSM fsm);

    ....

   protected int currentState;
   protected int previousState;

    .....
}

this should be work and it does. so i concluded using generic-delegate in MonoTouch is not a good idea at all.