13

Is there a rule when to use the native NSTimer versus the .NET alternatives?

  • System.Windows.Forms.Timer
  • System.Timers.Timer
  • System.Threading.Timer
Krumelur
  • 32,180
  • 27
  • 124
  • 263

5 Answers5

21

If you aim for portability, I'd use a .NET timer (see below) except if you have no other choices (like a NSTimer argument for a method call).

My all time favourite timer is unfortunately not listed in your question, is the one offered by the Task class:

await Task.Delay (20);
//do something after the delay

Usage is very simple. So instead of this Timer code:

void f() {
    var timer = new Timer(2000);
    timer.Elapsed += OnTimerElapsed;
    timer.Start ();
    Console.WriteLine ("Timer started, control is back here");
}

void OnTimerElasped (object o, EventArgs e)
{
    Console.WriteLine ("tick");
}

You can use this:

void f() {
    StartTimer ();
    Console.WriteLine ("Timer started, control is back here");
}

async void StartTimer ()
{
    while (true) {
        await Task.Delay (2000);
        Console.WriteLine ("tick");
    }
}

or if you want a single execution:

async void StartTimer ()
{
    await Task.Delay (2000);
    Console.WriteLine ("tick");
}

Which is a real benefit, as you don't need to keep the timer as instance variable just to be able to .Stop() it.

I find this form more streamlined. Just like we dismissed the goto statement years ago (GOTO isn't dead. It's on the island with Elvis and Joe Dassin), it's time to think about our callbacks overuse.

Stephane Delcroix
  • 16,134
  • 5
  • 57
  • 85
9

I suggest to use NSTimer.

Xamarin 5.10:

var sampleTimer = NSTimer.CreateRepeatingScheduledTimer (TimeSpan.FromSeconds (5.0), delegate {

    //Write Action Here
                }); 

and add a line To start the timer!

sampleTimer.Fire();

Stop after use:

    sampleTimer.Invalidate ();
    sampleTimer.Dispose ();
    sampleTimer = null;
UserID0908
  • 98
  • 1
  • 15
Alvin George
  • 14,148
  • 92
  • 64
6

IMO the prime rule is that anytime some types (or methods) offers duplicated features between .NET and the platform you're currently working on, you must consider your long term cross-platform goals for your application and that particular bit of code (reuse).

IOW code using NSTimer will only work on iOS and OSX. Using a .NET timer will work on Windows, Android and, of course, iOS and OSX.

poupou
  • 43,413
  • 6
  • 77
  • 174
  • Is it true what James has replied about the auto release pools? – Krumelur Oct 08 '13 at 12:29
  • 1
    The ThreadPool already has internal support for `NSAutoreleasePool` and support for `Thread` was added in 5.2, see http://spouliot.wordpress.com/2011/12/01/threading-and-pooling/ OTOH support for `Task` and `BackgroundWorker` still need special support (reusing the same thread needs to drain the pool) http://forums.xamarin.com/discussion/6404/memory-leaks-and-nsautoreleasepool – poupou Oct 08 '13 at 12:51
  • @poupou +1 I am sure I read about this issue a while ago, wasn't sure it had been addressed. I have deleted my answer based on your documentation link :) – James Oct 08 '13 at 12:57
2

Some answers recommend using .net timers for cross-platform goals. But the problem is that Timer class is not available in some PCL profiles (at least the profile Xamarin uses). In those cases, the workaround involves using Task.Delay() as @stephane-delcroix suggested. I even created a PclTimer utility class for that matter.

BUT...

I found a situation where Task.Delay() won´t work properly on iOS. If you try to use it within a background task:

var taskId = UIApplication.SharedApplication.BeginBackgroundTask(() => {});
// run your timer logic here with Task.Delay() 

you´ll find out that the intervals become corrupted (delayed), not respecting the interval you set on Task.Delay(interval).

In that scenario, NSTimer.CreateRepeatingScheduledTimer() works totally fine.

So I would say:

  • Do you need to run the timer in a background task? => Use NSTimer
  • You don´t need background tasks? => use .NET
Community
  • 1
  • 1
xleon
  • 6,201
  • 3
  • 36
  • 52
1

I agree with Poupou and Stephane, but I would also say "it depends". If you need to implement the timer in a common or shared part .Net alternatives are the best. Since the question is about Xamarin.iOS (not Xamarin.Android or Xamarin.Forms) I would like to add the following not listed (so far) solution that works for me and it's very simple.

NSTimer timer = NSTimer.CreateRepeatingScheduledTimer(TimeSpan.FromSeconds(3), delegate { MyMethod(); });

It Calls MyMethod(); every 3 seconds.

Daniele D.
  • 2,624
  • 3
  • 36
  • 42