iOS 5.1 vs stdout

The official release of Apple’s iOS 5.1 quickly made it clear that writing to stdout was not allowed anymore. Sadly it was not so visible, in the beta days, since it worked (and it still works today) when installing applications using MonoDevelop or Xcode.

So applications installed from the AppStore or by AdHoc distributions now get an access denied error when accessing stdout. That error resulted, in MonoTouch 5.2.3 (and earlier), in an UnauthorizedAccessException begin thrown and since it’s uncommonn to try/catch around WriteLine this could kill your application. Worse without stdout there would not be many hints about the root issue.

Newer versions of MonoTouch (5.2.4+) are fixed, i.e. they won’t throw an exception, so the application won’t crash. But that won’t give you back any logging capability unless you used (or started using) NSLog. If you need to log information in release builds then you still use Console with the following redirection helper class.

/// <summary>
/// An NSLog-backed TextWriter implementation to (re)enable our beloved Console.
/// note: printf coming from the Mono runtime (e.g. crash stacktraces) are not processed thru Console.* methods
/// <example>
/// var writer = new NSLogWriter ();
/// Console.SetOut (writer);
/// Console.WriteLine ("back into action!");
/// </example>
/// </summary>
class NSLogWriter : TextWriter {

	[DllImport (MonoTouch.Constants.FoundationLibrary)]
	extern static void NSLog (IntPtr format, string s);

	static NSString format = new NSString ("%s");

	StringBuilder sb;

	public NSLogWriter ()
		sb = new StringBuilder ();

	public override System.Text.Encoding Encoding {
		get { return System.Text.Encoding.UTF8; }

	public override void Flush ()
		// basic strings sanitation (for .NET developers {} habits)
		sb.Replace ("%", "%%");
		NSLog (format.Handle, sb.ToString ());
		sb.Length = 0;

	public override void Write (char value)
		sb.Append (value);

	// optimization (to avoid concatening chars)
	public override void Write (string value)
		sb.Append (value);

	public override void WriteLine ()
		Flush ();

The above class can be used like this (e.g. from your FinishedLaunching method):

Console.SetOut (new NSLogWriter ());
Console.WriteLine ("we're back in action!");

Logging, using either NSLog or Console.WriteLine has a cost. It’s also something most users won’t ever see as they don’t have the tools for it (unless they install the iPhone Configuation Utility). So it’s not surprising many people will frown upon this being used in released applications. Better used with moderation 🙂

If you do not need logging inside your released applications then it would be more useful to switch to Debug.WriteLine. Since Debug has [Conditional ("DEBUG")] attributes on its methods the logging won’t be part of non-debug builds (which should be what you release ;-). Also, because debug builds are run from MonoDevelop they will be able to access stdout.


About spouliot

Xamarin Hacker, Mono Contributor, Open Source Enthusiast with strong interests in Code Analysis, Cryptography and Security. Presently working on MonoTouch, previous projects were Moonlight and libgdiplus and a lot of the cryptographic work done on Mono.
This entry was posted in mono, monotouch, xamarin. Bookmark the permalink.

One Response to iOS 5.1 vs stdout

  1. Dennis says:

    Great post. Thanks for clarifying the issue and providing an alternative. I’ve never had any use for Console.Writeline in a released app but never remove them before released. I guess it’s just laziness. I’m going with Debug.Writeline option in the future. I’m currently using @Loggly for logging major issues and exceptions from the devices and love it.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s