I’ve been converting a major App and the Migrate tool works very well but I found a couple of cases, which either it didn’t do or I messed up.

The first is when using a nint as an index in a List. It doesn’t work, as the .NET generics know nothing about nints. So just cast it to an int like this below where _itemsList is a List

Text = _itemsList[(int)row];

Converting NSDate to System.DateTime and vice versa

It’s now a compile error to assign a DateTime to a NSDate or vice versa, the implicit conversion no longer works. I think this is to highlight a subtle bug to do with NSDate is always an UTC time and DateTime is default set to DateTimeKind.Unspecified (when read from database) or DateTimeKind.Locale (when set with DateTime.Today) Source is this stackoverflow answer.

Thankfully the Foundation.NSDate class includes two explicit operators that do the job for you.
NSDate in Xamarin Object Browser


So this works.

            NSDate nDate = (NSDate) DateTime.Now;
            DateTime dDate = (DateTime) nDate;

AVAudioRecorder Changes

The settings used to create an AVAudioRecorder have changed from a NSDictionary to AudioSettings, and the AVAudioRecorder.ToUrl method no longer exists.

Instead create avsettings like this and use the factory method Create to create the AVAudioRecorder.

//Set Settings with the Values and Keys to create the NSDictionary
            avsettings = new AudioSettings(NSDictionary.FromObjectsAndKeys(values, keys));

//Set recorder parameters
            recorder = AVAudioRecorder.Create(url, avsettings, out error);

Near the end of a project and there’s nothing worse than getting a new release of the development software and getting a real big scare. I got 7.0.4 this morning with the new pairing of Visual Studio to the Xamarin.iOS Build Host running on the Mac.

Mac and Windows Pairing Dialogs

That worked well, but the scare came when I went to upload the newly built app on to my device and got a No Provisioning Profiles Found build error. Weird but as I’d renewed my developer account with Apple yesterday, possibly it was related to that but no it showed fine. The profiles on the iPhone showed fine as well in the Xcode organiser.

Dev profiles in Xcode's organiser

I was a bit worried because my Mac is only 10.7.5 and can’t run Xcode 5 or develop for iOS 7. It will be replaced shortly. However it turned out to be a lot simpler than that. In the Xamarin Studio Preferences, the Developer accounts had been zapped. Just adding my Apple account back in sorted it.

Xamarin Studio Developer Accounts

There are plenty of logging systems about for .NET. This site although it’s an advert for a .NET logging system has links and comparisons with many.  But sometimes all you need is a very simple logger, something as simple as appending a string to a text file. So here’s a 64 line logger that creates a dailyfile – for today it’s 20131004.log.

using System;
using System.IO;
using System.Threading.Tasks;

namespace TMRTaxi
{
    class Logger : IDisposable
    {
        public string FileName { get; set; }
        private StreamWriter sw;

        public Logger()
        {
            var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var cache = Path.Combine(documents, "..", "Library", "Caches");
            var logfile = Path.Combine(cache, @"log" + DateTime.Now.ToString("yyyymmdd") + ".log");
            FileName = logfile;
            var str = "Logging Startedn";

            sw = new StreamWriter(FileName, true);
            Log(str);

        }

        public void Pause()
        {
            if (sw != null)
            {
                sw.Flush();
                sw.Close();
                sw = null;
            }            
        }

        public void Log(string msg,string comment="")
        {
            if (sw == null)
                return;
            msg = DateTime.Now.ToString("T") + " : "+msg+(comment != ""?" ["+comment+"]":"");
            Task.Factory.StartNew(()=> sw.WriteLine(msg), TaskCreationOptions.LongRunning);           
        }

        public void Dispose(Boolean disposing)
        {
            if (sw != null)
            {
                sw.Close();
                sw = null;
            }    
        }

        public void Dispose()
        {
            Dispose(true); //i am calling you from Dispose, it's safe
            GC.SuppressFinalize(this); //Hey, GC: don't bother calling finalize later
        }

        ~Logger()
        {
            Dispose(false); //i am *not* calling you from Dispose, it's *not* safe
        }
    }
}

It could probably do with a bit of extra error checking. A try catch round the sw = new StreamWriter(FileName, true); line for instance.

These lines:

var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var cache = Path.Combine(documents, "..", "Library", "Caches");
            var logfile = Path.Combine(cache, @"log" + DateTime.Now.ToString("yyyymmdd") + ".log");

create the log file in the caches folder.

This line Task.Factory.StartNew(()=> sw.WriteLine(msg), TaskCreationOptions.LongRunning); in Log() does a fire and forget. It runs it using the TPL (Task Parallel library). It seems to work fine.

Just creature a logger with

log = new Logger();
log.Log("App starting up");

Plus there’s an optional comment on the Log method.

Of course it would be nice if you can email the logs to yourself but programmatically that’s a no no. “Apfel verbietet es” as my German teacher might have said. (“Apple forbids it.”).

The workaround is to build a large text file from all the available log files (and remove them afterwards) then post it to a php script on a website and it emails it. I’ll post the C# code for that in a day or two.

Here’s proof- well it works in the simulator anyway!

ios-simulator