I am trying to add a timer to my iOS application, for this I use the following code:
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace MyNamespace
{
[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
UIWindow window;
public static NavigationController MyNavigationController;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
RectangleF bounds = UIScreen.MainScreen.Bounds;
MyNavigationController = new NavigationController(bounds);
window = new UIWindow (bounds);
window.RootViewController = MyNavigationController;
window.MakeKeyAndVisible ();
return true;
}
}
public class NavigationController : UINavigationController
{
private RectangleF _bounds;
private RectangleF _viewPort;
public NavigationController(RectangleF bounds)
{
_bounds = bounds;
NavigationBar.BarStyle = UIBarStyle.Black;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
_viewPort = new RectangleF(_bounds.Location, new SizeF(_bounds.Width, _bounds.Height - NavigationBar.Frame.Height));
ShowFirstView(); // Default to showing FirstViewController
}
public void ShowFirstView()
{
PushViewController(new FirstViewController(_viewPort), true);
}
public void ShowSecondView()
{
PushViewController(new SecondViewController(_viewPort), true);
}
}
public class FirstViewController : UIViewController
{
public FirstViewController(RectangleF bounds)
{
// Empty view
View = new UIView(bounds);
View.BackgroundColor = UIColor.White;
Title = "First View";
// Simple button to navigate to next view
UIButton button = UIButton.FromType(UIButtonType.RoundedRect);
button.Frame = new RectangleF(10,10,300,30);
button.SetTitle("Show next view", UIControlState.Normal);
button.TouchUpInside += (sender, e) => { AppDelegate.MyNavigationController.ShowSecondView(); };
View.AddSubview(button);
}
}
public class SecondViewController : UIViewController
{
private NSTimer _timer;
public SecondViewController(RectangleF bounds)
{
// Empty View
View = new UIView(bounds);
View.BackgroundColor = UIColor.Blue;
Title = "Second View";
// Create timer
_timer = NSTimer.CreateRepeatingScheduledTimer(2f, delegate { Console.WriteLine("Timer Fired"); });
}
}
}
When I run this code in the Simulator it works as expected, writing out "Timer Fired" to the console every 2 seconds.
However when I attach Apple Instruments, specifically the Allocations Instrument an exception is thrown at UIApplication.Main (args, null, "AppDelegate");
in Main.cs
Selector invoked from objective-c on a managed object of type MonoTouch.Foundation.NSActionDispatcher (0x10AA2D50) that has been GC'ed
Stack Trace:
System.Exception: Selector invoked from objective-c on a managed object of type MonoTouch.Foundation.NSActionDispatcher (0x14FB5AC0) that has been GC'ed ---> System.Exception: No constructor found for MonoTouch.Foundation.NSActionDispatcher::.ctor(System.IntPtr)
at System.Activator.CreateInstance (System.Type type, BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) [0x000f1] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System/Activator.cs:280
at System.Activator.CreateInstance (System.Type type, System.Object[] args, System.Object[] activationAttributes) [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System/Activator.cs:234
at System.Activator.CreateInstance (System.Type type, System.Object[] args) [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System/Activator.cs:229
at MonoTouch.ObjCRuntime.Runtime.ConstructNSObject (IntPtr ptr, IntPtr klass) [0x0000d] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:231
--- End of inner exception stack trace ---
at MonoTouch.ObjCRuntime.Runtime.ConstructNSObject (IntPtr ptr, IntPtr klass) [0x00045] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:236
at MonoTouch.ObjCRuntime.Runtime.GetNSObject (IntPtr ptr) [0x0001f] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:280
at MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (IntPtr ptr) [0x00000] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:297
at (wrapper native-to-managed) MonoTouch.ObjCRuntime.Runtime:GetNSObjectWrapped (intptr)
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at MyNamescape.Application.Main (System.String[] args) [0x00000] in Main.cs:17
Key things to note:
NSActionDispatcher
in relation to this context, or otherwise in MonoTouchSo I am not sure if this is an issue with the Allocations Instrument or whether I am doing something profoundly wrong in my code. Any advise on this issue is greatly appreciated.
EDIT: I have updated the code to show the simplest complete application use case that causes the issue. (I have updated my timer code as per PouPou's comment regarding the unnecessary use of the thread)
UPDATE (Jan 17 2013): I have tried this using the iPad & iPhone simulators versions 5.0, 5.1 and 6.0, all produce the same result.
UPDATE (Jan 18 2013): Added native stack frames as per request of Rolf.
2013-01-18 13:28:47.579 TestTimer[12196:c07] at MonoTouch.ObjCRuntime.Runtime.ConstructNSObject (IntPtr ptr, IntPtr klass) [0x00045] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:236
at MonoTouch.ObjCRuntime.Runtime.GetNSObject (IntPtr ptr) [0x0001f] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:280
at MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (IntPtr ptr) [0x00000] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:297
at (wrapper native-to-managed) MonoTouch.ObjCRuntime.Runtime:GetNSObjectWrapped (intptr)
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at MyNamescape.Application.Main (System.String[] args) [0x00000] in Main.cs:16
2013-01-18 13:28:47.623 TestTimer[12196:c07] 0 TestTimer 0x00093a22 mono_handle_exception_internal_first_pass + 3058
1 TestTimer 0x00095102 mono_handle_exception_internal + 1602
2 TestTimer 0x00095c4f mono_handle_exception + 47
3 TestTimer 0x000dda72 mono_x86_throw_exception + 306
4 ??? 0x0b3e0f8f 0x0 + 188616591
at MonoTouch.ObjCRuntime.Runtime.GetNSObject (intptr) [0x0001f] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:280
at MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (intptr) [0x00000] in /Developer/MonoTouch/Source/monotouch/src/ObjCRuntime/Runtime.cs:297
at (wrapper native-to-managed) MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (intptr) <IL 0x00017, 0x00094>
8 TestTimer 0x00224873 get_managed_object_for_ptr + 115
9 TestTimer 0x00229700 monotouch_trampoline + 448
10 Foundation 0x019b9b90 __NSFireTimer + 97
11 CoreFoundation 0x01315376 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
12 CoreFoundation 0x01314e06 __CFRunLoopDoTimer + 534
13 CoreFoundation 0x012fca82 __CFRunLoopRun + 1810
14 CoreFoundation 0x012fbf44 CFRunLoopRunSpecific + 276
15 CoreFoundation 0x012fbe1b CFRunLoopRunInMode + 123
16 GraphicsServices 0x04b807e3 GSEventRunModal + 88
17 GraphicsServices 0x04b80668 GSEventRun + 104
18 UIKit 0x0273965c UIApplicationMain + 1211
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x00056, 0x001f5>
at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at MyNamescape.Application.Main (string[]) [0x00000] in Main.cs:16
at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00049, 0x0014e>
23 TestTimer 0x00010252 mono_jit_runtime_invoke + 722
24 TestTimer 0x0017478e mono_runtime_invoke + 126
25 TestTimer 0x00178be4 mono_runtime_exec_main + 420
26 TestTimer 0x00178f55 mono_runtime_run_main + 725
27 TestTimer 0x0006ba65 mono_jit_exec + 149
28 TestTimer 0x0021f65d main + 2013
29 TestTimer 0x00003125 start + 53
I've (finally) tracked this down to be a bug in MonoTouch (Instruments intercepts the retain/release methods, which confuses MonoTouch). The bug has been fixed, and will be included in the next stable version (6.0.9).