Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSTimer versus Timer in Xamarin.iOS - when to use what?

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

  • System.Windows.Forms.Timer
  • System.Timers.Timer
  • System.Threading.Timer
like image 727
Krumelur Avatar asked Oct 08 '13 09:10

Krumelur


4 Answers

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
like image 103
xleon Avatar answered Oct 25 '22 10:10

xleon


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;
like image 33
Alvin George Avatar answered Nov 14 '22 00:11

Alvin George


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.

like image 21
Stephane Delcroix Avatar answered Nov 14 '22 00:11

Stephane Delcroix


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.

like image 6
poupou Avatar answered Nov 14 '22 02:11

poupou