<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Steve Saxon</title>
	<atom:link href="http://www.stevesaxon.me/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.stevesaxon.me</link>
	<description>Steve Saxon&#039;s blog</description>
	<lastBuildDate>Sun, 18 Sep 2011 17:09:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Simple async file access using Windows 8, part 2</title>
		<link>http://www.stevesaxon.me/posts/2011/windows8-async-file-access-2/</link>
		<comments>http://www.stevesaxon.me/posts/2011/windows8-async-file-access-2/#comments</comments>
		<pubDate>Thu, 15 Sep 2011 20:18:39 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Windows Runtime]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=226</guid>
		<description><![CDATA[In the previous article I presented a helper library for reading and writing to the file system using the new Windows Runtime asynchronous file APIs. One downside of the code &#8230;]]></description>
			<content:encoded><![CDATA[<p>In the <a href="/posts/2011/windows8-async-file-access/" target="_blank">previous article</a> I presented a helper library for reading and writing to the file system using the new Windows Runtime asynchronous file APIs.</p>
<p>One downside of the code I presented is that the actual reading and writing was still happening on the main UI thread. While this may not be a problem in a simple application, it is undesirable for complex documents.</p>
<p>The challenge is that we still need to be on the UI thread when we collect the data we want to save, but the writing itself could be on a background thread.</p>
<p>In this article I will cover a way to extend the API I presented previously, to allowing reading and writing via a background thread.<span id="more-226"></span></p>
<h3>Reading on the background thread</h3>
<p>One key tenet to reading in the background is that we need to load all of the data in before we update the UI. Think of a Microsoft Word document being loaded into memory in the background in its in-memory format, then only presenting it in the UI once the load has completed.</p>
<p>This is how we want to write our reading code:</p>
<pre class="csharp codeblock">FileAsync<span class="sy0">.</span><span class="me1">Read</span><span class="sy0">&lt;</span><span class="kw4">string</span><span class="sy0">&gt;</span><span class="br0">&#40;</span>KnownFolders<span class="sy0">.</span><span class="me1">DocumentsLibrary</span>, <span class="st0">&quot;myfile.txt&quot;</span>,
    <span class="br0">&#40;</span>fileSize, reader<span class="br0">&#41;</span> <span class="sy0">=&gt;</span> reader<span class="sy0">.</span><span class="me1">ReadString</span><span class="br0">&#40;</span>fileSize<span class="br0">&#41;</span>  <span class="coMULTI">/* read in the background */</span>,
    text <span class="sy0">=&gt;</span> EditBox<span class="sy0">.</span><span class="me1">Text</span> <span class="sy0">=</span> text  <span class="coMULTI">/* update the UI on the main thread */</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>
<p>The example here is very simple, as our in memory &#8220;document&#8221; is a single string. In an application build using the MVVM pattern (Model-View-ViewModel), this would be a great way to load the Model in from a file, and finally bind it into the ViewModel once it has loaded through the two steps shown above.</p>
<p>Here is the implementation of the <code>Read</code> method:</p>
<pre class="csharp codeblock"><span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">async</span> <span class="kw4">void</span> Read<span class="sy0">&lt;</span>TDocument<span class="sy0">&gt;</span><span class="br0">&#40;</span>StorageFolder folder, <span class="kw4">string</span> fileName,
Func<span class="sy0">&lt;</span><span class="kw4">uint</span>, DataReader, TDocument<span class="sy0">&gt;</span> reader, Action<span class="sy0">&lt;</span>TDocument<span class="sy0">&gt;</span> completion <span class="sy0">=</span> <span class="kw1">null</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    StorageFile file<span class="sy0">;</span>
    IRandomAccessStream stream<span class="sy0">;</span>
    IInputStream inputStream<span class="sy0">;</span>
    DataReader dr<span class="sy0">;</span>
&nbsp;
    file <span class="sy0">=</span> <span class="kw1">await</span> folder<span class="sy0">.</span><span class="me1">GetFileAsync</span><span class="br0">&#40;</span>fileName<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    stream <span class="sy0">=</span> <span class="kw1">await</span> file<span class="sy0">.</span><span class="me1">OpenAsync</span><span class="br0">&#40;</span>FileAccessMode<span class="sy0">.</span><span class="me1">Read</span><span class="br0">&#41;</span><span class="sy0">;</span>
    inputStream <span class="sy0">=</span> stream<span class="sy0">.</span><span class="me1">GetInputStreamAt</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw4">uint</span> fileSize <span class="sy0">=</span> <span class="br0">&#40;</span><span class="kw4">uint</span><span class="br0">&#41;</span>stream<span class="sy0">.</span><span class="me1">Size</span><span class="sy0">;</span>
&nbsp;
    dr <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> DataReader<span class="br0">&#40;</span>inputStream<span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">await</span> dr<span class="sy0">.</span><span class="me1">LoadAsync</span><span class="br0">&#40;</span>fileSize<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    Task<span class="sy0">&lt;</span>TDocument<span class="sy0">&gt;</span> task <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> Task<span class="sy0">&lt;</span>TDocument<span class="sy0">&gt;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> reader<span class="br0">&#40;</span>fileSize, dr<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    task<span class="sy0">.</span><span class="me1">Start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    TDocument doc <span class="sy0">=</span> <span class="kw1">await</span> task<span class="sy0">;</span>
&nbsp;
    <span class="kw1">if</span> <span class="br0">&#40;</span>completion <span class="sy0">!=</span> <span class="kw1">null</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        completion<span class="br0">&#40;</span>doc<span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>
<p>Here we used the new Task class, which is what underpins the <code>await</code> and <code>async</code> keywords.</p>
<h3>Writing</h3>
<p>Writing to the file involves creating the &#8220;document&#8221; on the UI thread (while may mean simply passing your Model if you are using MVVM). The <code>Write</code> method will then call you asynchronously to get the document written out.</p>
<pre class="csharp codeblock">FileAsync<span class="sy0">.</span><span class="me1">Write</span><span class="sy0">&lt;</span><span class="kw4">string</span><span class="sy0">&gt;</span><span class="br0">&#40;</span>KnownFolders<span class="sy0">.</span><span class="me1">DocumentsLibrary</span>, <span class="st0">&quot;myfile.txt&quot;</span>,
   CreationCollisionOption<span class="sy0">.</span><span class="me1">ReplaceExisting</span>,
   EditBox<span class="sy0">.</span><span class="me1">Text</span>, <span class="coMULTI">/* pass in our &quot;document&quot; content */</span>
    <span class="br0">&#40;</span>w, doc<span class="br0">&#41;</span> <span class="sy0">=&gt;</span> w<span class="sy0">.</span><span class="me1">WriteString</span><span class="br0">&#40;</span>doc<span class="br0">&#41;</span> <span class="coMULTI">/* write the &quot;document&quot; in the background */</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>
<p>Much like the <code>Read</code> method, <code>Write</code> leverages <code>Task</code> to perform the writing.</p>
<pre class="csharp codeblock"><span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">async</span> <span class="kw4">void</span> Write<span class="sy0">&lt;</span>TDocument<span class="sy0">&gt;</span><span class="br0">&#40;</span>StorageFolder folder, <span class="kw4">string</span> fileName,
    CreationCollisionOption collisionOption, TDocument doc,
    Action<span class="sy0">&lt;</span>DataWriter, TDocument<span class="sy0">&gt;</span> writer, Action<span class="sy0">&lt;</span><span class="kw4">bool</span><span class="sy0">&gt;</span> complete <span class="sy0">=</span> <span class="kw1">null</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    StorageFile creator<span class="sy0">;</span>
    IRandomAccessStream stream<span class="sy0">;</span>
    IOutputStream outputStream<span class="sy0">;</span>
    DataWriter dw<span class="sy0">;</span>
&nbsp;
    creator <span class="sy0">=</span> <span class="kw1">await</span> folder<span class="sy0">.</span><span class="me1">CreateFileAsync</span><span class="br0">&#40;</span>fileName, collisionOption<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    stream <span class="sy0">=</span> <span class="kw1">await</span> creator<span class="sy0">.</span><span class="me1">OpenAsync</span><span class="br0">&#40;</span>FileAccessMode<span class="sy0">.</span><span class="me1">ReadWrite</span><span class="br0">&#41;</span><span class="sy0">;</span>
    outputStream <span class="sy0">=</span> stream<span class="sy0">.</span><span class="me1">GetOutputStreamAt</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    dw <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> DataWriter<span class="br0">&#40;</span>outputStream<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    Task task <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> Task<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">=&gt;</span> writer<span class="br0">&#40;</span>dw, doc<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    task<span class="sy0">.</span><span class="me1">Start</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">await</span> task<span class="sy0">;</span>
&nbsp;
    <span class="kw1">await</span> dw<span class="sy0">.</span><span class="me1">StoreAsync</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw4">bool</span> success <span class="sy0">=</span> <span class="kw1">await</span> outputStream<span class="sy0">.</span><span class="me1">FlushAsync</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span>complete <span class="sy0">!=</span> <span class="kw1">null</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        complete<span class="br0">&#40;</span>success<span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>
<p>As you can see, the Windows Runtime makes it really easy to create asynchronously called code. With very little code we were able to take our earlier code, and with a little refactoring, enable the reading and writing to be fully performed on a background thread. Windows 8 should allow developers to create really great apps that stay responsive even when performing lengthy operations. When its this easy to achieve, this should become the rule rather than the exception.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/windows8-async-file-access-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple async file access using Windows 8</title>
		<link>http://www.stevesaxon.me/posts/2011/windows8-async-file-access/</link>
		<comments>http://www.stevesaxon.me/posts/2011/windows8-async-file-access/#comments</comments>
		<pubDate>Thu, 15 Sep 2011 16:42:51 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Windows Runtime]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=206</guid>
		<description><![CDATA[This article refers to pre-release software. Some or all of what is presented could change between now and release. This week at the Build Windows conference, Microsoft announced Windows 8 &#8230;]]></description>
			<content:encoded><![CDATA[<p><i>This article refers to pre-release software. Some or all of what is presented could change between now and release.</i></p>
<p>This week at the Build Windows conference, Microsoft announced Windows 8 and introduced the new Windows Runtime APIs for the developers.</p>
<p>As a C# developer, one of the defining features of the Runtime is that a lot of the .NET Framework is &#8220;gone&#8221;, or moved to new namespaces. Nowhere is this more true than in <code>System.IO</code>, which is now fairly barren. The reason is that most of the file I/O APIs in the Windows Runtime are designed to be asynchronous, and as these new APIs are in the Runtime, they&#8217;ve moved into the Windows.* namespace.</p>
<p>As it turns out, reading and writing files using the new asynchronous APIs is a little convoluted. OK, its a lot convoluted, but I&#8217;ve put together some code that should simplify it for you, while also taking you through the steps involved.<span id="more-206"></span></p>
<p>When I think of reading or writing a file synchronously, I think of moving the reading or writing operation into a delegate that will be called for me when the time comes. For example, I would want to read a file asynchronously from our Documents library using code like this:</p>
<pre class="csharp codeblock">FileAsync<span class="sy0">.</span><span class="me1">Read</span><span class="br0">&#40;</span>KnownFolders<span class="sy0">.</span><span class="me1">DocumentsLibrary</span>, <span class="st0">&quot;myfile.txt&quot;</span>, <span class="br0">&#40;</span>fileSize, reader<span class="br0">&#41;</span> <span class="sy0">=&gt;</span>
    <span class="br0">&#123;</span>
        <span class="kw4">string</span> text <span class="sy0">=</span> reader<span class="sy0">.</span><span class="me1">ReadString</span><span class="br0">&#40;</span>fileSize<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
        <span class="kw1">this</span><span class="sy0">.</span><span class="me1">EditBox</span><span class="sy0">.</span><span class="me1">Text</span> <span class="sy0">=</span> text<span class="sy0">;</span>
    <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>
<p>Let&#8217;s see what is needed to make this work.</p>
<p>First let&#8217;s pull in the namespaces we&#8217;ll need:</p>
<pre class="csharp codeblock"><span class="kw1">using</span> <span class="co3">System</span><span class="sy0">;</span>
<span class="kw1">using</span> <span class="co3">Windows.Storage</span><span class="sy0">;</span>
<span class="kw1">using</span> <span class="co3">Windows.Storage.Streams</span><span class="sy0">;</span></pre>
<p>Now let&#8217;s create the shell of our class&#8230;</p>
<pre class="csharp codeblock"><span class="kw1">namespace</span> SteveSaxon<span class="sy0">.</span><span class="me1">IO</span>
<span class="br0">&#123;</span>
    <span class="kw1">public</span> <span class="kw1">static</span> <span class="kw4">class</span> FileAsync
    <span class="br0">&#123;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>
<p>Next we&#8217;ll add support for reading files. This may seem overly complicated, but the <code>await</code> keyword is greatly simplifying it for us. In a nutshell, <code>await</code> allows you to make a call on a background thread, such that once it completes, the result of the call is dispatched back to the thread you made the call from. You get to write fairly natural looking code knowing that you&#8217;re never blocking the calling thread, but getting to take full advantage of all of the computing power in your system.</p>
<table bgcolor="#ffffdd">
<tr>
<td>Eric Lippert <a href="http://blogs.msdn.com/b/ericlippert/archive/2010/10/29/asynchronous-programming-in-c-5-0-part-two-whence-await.aspx" target="_blank">posted a great article</a> on how the <code>await</code> and <code>async</code> keywords work.</td>
</tr>
</table>
<p>Better yet, if your asynchronous call ends up throwing an exception, this exception gets thrown in your calling thread too, so the exception case is also extremely elegant.</p>
<table bgcolor="#ffffdd">
<tr>
<td>Eric <a href="http://blogs.msdn.com/b/ericlippert/archive/2010/11/19/asynchrony-in-c-5-part-seven-exceptions.aspx" target="_blank">also posted an article</a> on how the exception work with <code>await</code> blocks.</td>
</tr>
</table>
<p>Here is the code for our <code>Read</code> method:</p>
<pre class="csharp codeblock"><span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">async</span> <span class="kw4">void</span> Read<span class="br0">&#40;</span>StorageFolder folder, <span class="kw4">string</span> fileName,
    Action<span class="sy0">&lt;</span><span class="kw4">uint</span>, DataReader<span class="sy0">&gt;</span> reader<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    StorageFile file<span class="sy0">;</span>
    IRandomAccessStream stream<span class="sy0">;</span>
    IInputStream inputStream<span class="sy0">;</span>
    DataReader rdr<span class="sy0">;</span>
&nbsp;
    file <span class="sy0">=</span> <span class="kw1">await</span> folder<span class="sy0">.</span><span class="me1">GetFileAsync</span><span class="br0">&#40;</span>fileName<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    stream <span class="sy0">=</span> <span class="kw1">await</span> file<span class="sy0">.</span><span class="me1">OpenAsync</span><span class="br0">&#40;</span>FileAccessMode<span class="sy0">.</span><span class="me1">Read</span><span class="br0">&#41;</span><span class="sy0">;</span>
    inputStream <span class="sy0">=</span> stream<span class="sy0">.</span><span class="me1">GetInputStreamAt</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw4">uint</span> fileSize <span class="sy0">=</span> <span class="br0">&#40;</span><span class="kw4">uint</span><span class="br0">&#41;</span>stream<span class="sy0">.</span><span class="me1">Size</span><span class="sy0">;</span>
&nbsp;
    rdr <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> DataReader<span class="br0">&#40;</span>inputStream<span class="br0">&#41;</span><span class="sy0">;</span>
    rdr<span class="sy0">.</span><span class="me1">LoadAsync</span><span class="br0">&#40;</span>fileSize<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    reader<span class="br0">&#40;</span>fileSize, rdr<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre>
<p>The <code>StorageFolder</code> first parameter may seem confusing, but it is the return type for the constants in the <code>KnownFolders</code> class, such <code>KnownFolders.DocumentsLibrary</code> and <code>KnownFolders.PicturesLibrary</code>.</p>
<p>One thing you may have noticed in the sample I presented: I was setting the text of an control in the UI based on the data I read in. In order for that to work, our delegate must have been called on the main thread, and in fact that is exactly what happens when you use <code>await</code>. When you issue an await, the awaited code is called on another thread, then joined back to the main thread when it completes.</p>
<p>If we had not been on the main thread, we would have needed to use code like this to marshal it back to the UI thread:</p>
<pre class="csharp codeblock"><span class="kw1">this</span><span class="sy0">.</span><span class="me1">Dispatcher</span><span class="sy0">.</span><span class="me1">InvokeAsync</span><span class="br0">&#40;</span>Windows<span class="sy0">.</span><span class="me1">UI</span><span class="sy0">.</span><span class="me1">Core</span><span class="sy0">.</span><span class="me1">CoreDispatcherPriority</span><span class="sy0">.</span><span class="me1">Normal</span>,
            <span class="br0">&#40;</span>dummy, args<span class="br0">&#41;</span> <span class="sy0">=&gt;</span> <span class="kw1">this</span><span class="sy0">.</span><span class="me1">EditBox</span><span class="sy0">.</span><span class="me1">Text</span> <span class="sy0">=</span> text, <span class="kw1">this</span>, <span class="kw1">null</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>
<p>Now you can see how elegant the <code>await</code> keyword is!</p>
<p>To simplify using the code with any folder on our disk let&#8217;s add the following helper function:</p>
<pre class="csharp codeblock"><span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">async</span> <span class="kw4">void</span> Read<span class="br0">&#40;</span><span class="kw4">string</span> folderPath, <span class="kw4">string</span> fileName,
        Action<span class="sy0">&lt;</span><span class="kw4">uint</span>, DataReader<span class="sy0">&gt;</span> reader<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    StorageFolder folder <span class="sy0">=</span> <span class="kw1">await</span> StorageFolder<span class="sy0">.</span><span class="me1">GetFolderFromPathAsync</span><span class="br0">&#40;</span>folderPath<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    Read<span class="br0">&#40;</span>folder, fileName, reader<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre>
<p>Writing is even more steps than reading, but we&#8217;ll try to make it simple. I&#8217;ve included the folder helper here too:</p>
<pre class="csharp codeblock"><span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">async</span> <span class="kw4">void</span> Write<span class="br0">&#40;</span>StorageFolder folder, <span class="kw4">string</span> fileName,
        CreationCollisionOption collisionOption, Action<span class="sy0">&lt;</span>DataWriter<span class="sy0">&gt;</span> writer,
        Action<span class="sy0">&lt;</span><span class="kw4">bool</span><span class="sy0">&gt;</span> complete <span class="sy0">=</span> <span class="kw1">null</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    StorageFile creator<span class="sy0">;</span>
    IRandomAccessStream stream<span class="sy0">;</span>
    IOutputStream outputStream<span class="sy0">;</span>
    DataWriter dw<span class="sy0">;</span>
&nbsp;
    creator <span class="sy0">=</span> <span class="kw1">await</span> folder<span class="sy0">.</span><span class="me1">CreateFileAsync</span><span class="br0">&#40;</span>fileName, collisionOption<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    stream <span class="sy0">=</span> <span class="kw1">await</span> creator<span class="sy0">.</span><span class="me1">OpenAsync</span><span class="br0">&#40;</span>FileAccessMode<span class="sy0">.</span><span class="me1">ReadWrite</span><span class="br0">&#41;</span><span class="sy0">;</span>
    outputStream <span class="sy0">=</span> stream<span class="sy0">.</span><span class="me1">GetOutputStreamAt</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    dw <span class="sy0">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span class="kw3">new</span></a> DataWriter<span class="br0">&#40;</span>outputStream<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    writer<span class="br0">&#40;</span>dw<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    <span class="kw1">await</span> dw<span class="sy0">.</span><span class="me1">StoreAsync</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw4">bool</span> success <span class="sy0">=</span> <span class="kw1">await</span> outputStream<span class="sy0">.</span><span class="me1">FlushAsync</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="kw1">if</span> <span class="br0">&#40;</span>complete <span class="sy0">!=</span> <span class="kw1">null</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        complete<span class="br0">&#40;</span>success<span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw1">public</span> <span class="kw1">static</span> <span class="kw1">async</span> <span class="kw4">void</span> Write<span class="br0">&#40;</span><span class="kw4">string</span> folderPath, <span class="kw4">string</span> fileName,
        CreationCollisionOption collisionOption, Action<span class="sy0">&lt;</span>DataWriter<span class="sy0">&gt;</span> writer,
        Action<span class="sy0">&lt;</span><span class="kw4">bool</span><span class="sy0">&gt;</span> complete <span class="sy0">=</span> <span class="kw1">null</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    StorageFolder folder <span class="sy0">=</span> <span class="kw1">await</span> StorageFolder<span class="sy0">.</span><span class="me1">GetFolderFromPathAsync</span><span class="br0">&#40;</span>folderPath<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
    Write<span class="br0">&#40;</span>folder, fileName, collisionOption, writer, complete<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre>
<p>Notice how the Write code allows us to pass in a delegate that is called once the writing is complete. This is because when you write your content out, it may get buffered and may not get committed right away. The completed delegate will be called once all of the content has been safely saved away. This might be important if you want to disable the Save button in your UI until the previous Save has completely finished.</p>
<p>We can now write back to our file using this code, in the same simple way our Read operation did:</p>
<pre class="csharp codeblock">FileAsync<span class="sy0">.</span><span class="me1">Write</span><span class="br0">&#40;</span>KnownFolders<span class="sy0">.</span><span class="me1">DocumentsLibrary</span>, <span class="st0">&quot;myfile.txt&quot;</span>,
            CreationCollisionOption<span class="sy0">.</span><span class="me1">ReplaceExisting</span>, w <span class="sy0">=&gt;</span>
                <span class="br0">&#123;</span>
                    w<span class="sy0">.</span><span class="me1">WriteString</span><span class="br0">&#40;</span><span class="kw1">this</span><span class="sy0">.</span><span class="me1">EditBox</span><span class="sy0">.</span><span class="me1">Text</span><span class="br0">&#41;</span><span class="sy0">;</span>
                <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>
<p>While asynchronous file I/O is still quite daunting in the Windows 8 Developer Preview, you can see how with a little work up front, it can be made quite elegant, while still retaining all of the power of its asynchronous nature.</p>
<p>In <a href="/posts/2011/windows8-async-file-access-2/">part 2 of this article</a> we will look at how to make the reading and writing operations themselves be asynchronous too.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/windows8-async-file-access/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My Daily submitted to the App Store</title>
		<link>http://www.stevesaxon.me/posts/2011/my-daily-submitted/</link>
		<comments>http://www.stevesaxon.me/posts/2011/my-daily-submitted/#comments</comments>
		<pubDate>Sat, 03 Sep 2011 02:58:06 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[mydaily]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=167</guid>
		<description><![CDATA[I have just submitted a new app to the App Store called My Daily. The purpose of the My Daily is to simplify entry into the Calendar for situations where &#8230;]]></description>
			<content:encoded><![CDATA[<p>I have just submitted a new app to the App Store called <strong><a href="/mydaily">My Daily</a></strong>.</p>
<p>The purpose of the My Daily is to simplify entry into the Calendar for situations where you are given a daily schedule of back-to-back tasks.</p>
<p><img src="/wp-content/uploads/2011/09/screen1.png" alt="My Daily main screen" width="320" height="480" /></p>
<p>The app allows you to set a daily start time. When you add an event, you pick the name from a list of names you define. Each name can be associated with a color swatch, allowing you to classify similar names with the same color.</p>
<p>Your first event will start at the daily start time, and subsequent events will start right after the previous event. Now you can add an event to your calendar by simply picking a name and clicking Save!</p>
<p><img src="/wp-content/uploads/2011/09/screen2.png" alt="My Daily edit screen" width="320" height="480" /></p>
<p>The neat thing is: if you delete an event, change its duration, or re-order the event, the start/end times are automatically updated. And the whole time, all of your changes are being synced into your iPhone&#8217;s Calendar, so you get all the same automatic alerts you expect.</p>
<p>And because My Daily syncs to your iPhone&#8217;s Calendar, each event can also have a reminder alert a few minutes before it is due to start. Reminders are also picked with a single click (no more navigating between screens).</p>
<p style="color:#c00">* Update &#8211; My Daily is now <a href="http://itunes.apple.com/us/app/my-daily/id461663816?ls=1&#038;mt=8">live in the App Store</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/my-daily-submitted/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPad HD&#8230; let it be true</title>
		<link>http://www.stevesaxon.me/posts/2011/ipad-hd-let-it-be-true/</link>
		<comments>http://www.stevesaxon.me/posts/2011/ipad-hd-let-it-be-true/#comments</comments>
		<pubDate>Fri, 15 Jul 2011 16:55:46 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Hardware]]></category>
		<category><![CDATA[iOS]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=164</guid>
		<description><![CDATA[Strictly one from the rumor mill, but I&#8217;m pretty pumped about the rumors of an upcoming iPad HD (or whatever they decide to call it). The short version is: a &#8230;]]></description>
			<content:encoded><![CDATA[<p>Strictly one from the rumor mill, but I&#8217;m pretty pumped about the rumors of an upcoming iPad HD (or whatever they decide to call it).</p>
<p>The short version is: a pro-sumer iPad intended for users of Apple&#8217;s pro-sumer apps such as Final Cut Pro. The device is rumored to have a 2048&#215;1536 Retina display (around 300dpi). I&#8217;d also expect to see 128GB of storage and LTE to store and move those big media files around.</p>
<p>Less sure is what it will look like. There were some rumors a few weeks ago that Apple was testing a black powder coat treatment for the MacBook Air, but then an alleged Apple engineer claimed it had been abandoned because of fingerprints. I guess I&#8217;m expecting the case to be black or dark grey to match the look of the pro-sumer apps, and to distinguish it from the regular (and much cheaper!) iPad 2. Apple even has an agreement to use LiquidMetal, which is darker than the aluminum on the &#8220;2&#8243;.</p>
<p>In other news, there was a rumor that Apple was looking to add a second manufacturer for the iPad alongside Foxconn, but this was quickly rebuffed with a statement to the effect of &#8220;Foxconn is still the exclusive manufacturer&#8221;. But what if what is happening is: Foxconn will start building the iPad HD at their Chengdu plant, while the existing Shenzen plant continues to build the iPad. So in that regard, the original rumor and the rebuff are both true.</p>
<p>Whatever it turns out to be, I know I&#8217;m going to want one.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/ipad-hd-let-it-be-true/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sharing a Mac screen via Live Meeting</title>
		<link>http://www.stevesaxon.me/posts/2011/sharing-a-mac-screen-via-live-meeting/</link>
		<comments>http://www.stevesaxon.me/posts/2011/sharing-a-mac-screen-via-live-meeting/#comments</comments>
		<pubDate>Fri, 10 Jun 2011 18:30:47 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=142</guid>
		<description><![CDATA[For those of you using a Mac in a largely Windows-based company, you may have times where you need to present content on your Mac from a PC running Live &#8230;]]></description>
			<content:encoded><![CDATA[<p>For those of you using a Mac in a largely Windows-based company, you may have times where you need to present content on your Mac from a PC running Live Meeting.</p>
<p>One fairly simple way to achieve this is by enabling Screen Sharing via System Preferences:</p>
<p><img src="/wp-content/uploads/2011/06/screensharing.png" /></p>
<p>Once Screen Sharing is enabled, you can run UltraVNC on your PC to connect to your Mac using the URL shown in the Screen Sharing window.</p>
<p>Now in Live Meeting, share your Desktop (or just share the UltraVNC window).</p>
<table bgcolor="#ffffdd">
<tr>
<td>Note: it is also possible to do this from inside a virtual machine on your Mac using VMWare Fusion or Parallels. However, the Mac Screen Sharing feature will share all of your screens, including the one where VMWare is running, meaning once you get VNC running in your virtual machine, you will want to use Cmd-H to immediately hide the virtual machine or get an infinitely recursing window tunnel!</p>
<p>Alternatively, <a href="http://simonguest.com/">Simon Guest</a> informs me that RealVNC Server for the Mac will let you specify which monitor is shared. You would want to use RealVNC Server in place of Mac Screen Sharing if you are going to try it this way. (You&#8217;ll get errors trying to use both on the same Mac as they would both be trying to use the same ports.</td>
</tr>
</table>
<p>If you are doing this using a separate PC talking to your Mac, don&#8217;t forget you are simply sharing your Mac screen, so the Mac keyboard and mouse can be used to control the action, making it more responsive than trying to use the PC keyboard and mouse via VNC.</p>
<table>
<tr>
<td nowrap="1">You can download UltraVNC here:</td>
<td><a href="http://www.uvnc.com/"><img src="http://cache.filehippo.com/img/ex/1174__ultraVNC2.png" border="0" /></a></td>
<td width="90%"><a href="http://www.uvnc.com/">http://www.ultravnc.com/</a></td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/sharing-a-mac-screen-via-live-meeting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Location-aware mobile web testing in iOS5</title>
		<link>http://www.stevesaxon.me/posts/2011/location-aware-mobile-web-testing-in-ios5/</link>
		<comments>http://www.stevesaxon.me/posts/2011/location-aware-mobile-web-testing-in-ios5/#comments</comments>
		<pubDate>Fri, 10 Jun 2011 18:06:51 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Mobile Web]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=126</guid>
		<description><![CDATA[One cool addition to Xcode 4.2 with iOS5 is the ability to test your location-aware application directly from inside Xcode through the same Edit Scheme screen you use to set &#8230;]]></description>
			<content:encoded><![CDATA[<p>One cool addition to Xcode 4.2 with iOS5 is the ability to test your location-aware application directly from inside Xcode through the same Edit Scheme screen you use to set up Environment Variables and command line arguments.</p>
<p><img src="/wp-content/uploads/2011/06/locawareweb-scheme.png" /></p>
<p>One current limitation is you can&#8217;t directly leverage this to test your mobile web sites, although the Simulator does provide some boilerplate locations built in.</p>
<p>A workaround is to create a small Universal iOS app in Xcode, and tell it to load your mobile web site&#8217;s URL during applicationDidFinishLaunching.
<pre class="objc codeblock"><span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">BOOL</span><span class="br0">&#41;</span>application<span class="sy0">:</span><span class="br0">&#40;</span>UIApplication <span class="sy0">*</span><span class="br0">&#41;</span>application
        didFinishLaunchingWithOptions<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span class="kw5">NSDictionary</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>launchOptions
<span class="br0">&#123;</span>
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span class="kw5">NSURL</span></a><span class="sy0">*</span> url <span class="sy0">=</span> <span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span class="kw5">NSURL</span></a> URLWithString<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;http://www.google.com/&quot;</span><span class="br0">&#93;</span>;
    <span class="br0">&#91;</span>application openURL<span class="sy0">:</span>url<span class="br0">&#93;</span>;
&nbsp;
    <a href="http://www.opengroup.org/onlinepubs/009695399/functions/exit.html"><span class="kw3">exit</span></a><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>; <span class="co2">// remove this to keep the debugger running!</span>
&nbsp;
    <span class="kw1">return</span> <span class="kw2">YES</span>;
<span class="br0">&#125;</span></pre>
<p>I can now use Edit Scheme to set my location, or create multiple schemes each for a different location. When I run this application, the GPS will be initialized with my prescribed location, then Safari will be invoked to open the URL I provided.</p>
<p><a href="/wp-content/uploads/2011/06/locawareweb-safari1.png"><img src="/wp-content/uploads/2011/06/locawareweb-safari1-154x300.png" /></a>  <a href="/wp-content/uploads/2011/06/locawareweb-safari2.png"><img src="/wp-content/uploads/2011/06/locawareweb-safari2-154x300.png" /></a></p>
<p>(Notice how in the second image Google is providing the &#8220;See Places Near&#8221; using the London location I provided).</p>
<p>By removing the <code>exit(0)</code> statement, it should even be possible to leverage the GPS automation capabilities provided by the new version of Instruments to automate the location over time and have Safari pick that up, though I haven&#8217;t had time to test this.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/location-aware-mobile-web-testing-in-ios5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ContentBundle demo updated</title>
		<link>http://www.stevesaxon.me/posts/2011/contentbundle-demo-updated/</link>
		<comments>http://www.stevesaxon.me/posts/2011/contentbundle-demo-updated/#comments</comments>
		<pubDate>Sat, 28 May 2011 16:21:53 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[iOS]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=114</guid>
		<description><![CDATA[I&#8217;ve updated the demo app for the ContentBundle application. The application now presents a UIWebView showing HTML from the ZIP file. An Update button causes the app to reach out &#8230;]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve updated the demo app for the ContentBundle application. The application now presents a UIWebView showing HTML from the ZIP file.</p>
<p>An Update button causes the app to reach out to the server and reload the page.</p>
<p>The screenshots below show the app before and after updating:</p>
<p><img src="http://www.stevesaxon.me/wp-content/uploads/2011/05/contentbundle-img1.png" alt="" /> <img src="http://www.stevesaxon.me/wp-content/uploads/2011/05/contentbundle-img2.png" alt="" /><span id="more-114"></span>The app is fairly simple. We wired up the RootViewController to use a UIWebView, and wired up the Update button all in Interface Builder.</p>
<p>In <b>viewDidLoad</b> we load the initial content:
<pre class="objc codeblock"><span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>viewDidLoad
<span class="br0">&#123;</span>
    <span class="br0">&#91;</span>super viewDidLoad<span class="br0">&#93;</span>;
&nbsp;
    SSContentBundle<span class="sy0">*</span> provider <span class="sy0">=</span> <span class="br0">&#91;</span>SSContentBundle mainBundle<span class="br0">&#93;</span>;
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> docPath <span class="sy0">=</span> <span class="br0">&#91;</span>provider pathForFile<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;index.html&quot;</span><span class="br0">&#93;</span>;
&nbsp;
    NSLog<span class="br0">&#40;</span><span class="co3">@</span><span class="st0">&quot;Path to index.html: %@&quot;</span>, docPath<span class="br0">&#41;</span>;
&nbsp;
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span class="kw5">NSURL</span></a><span class="sy0">*</span> url <span class="sy0">=</span> <span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span class="kw5">NSURL</span></a> fileURLWithPath<span class="sy0">:</span>docPath<span class="br0">&#93;</span>;
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/"><span class="kw5">NSURLRequest</span></a><span class="sy0">*</span> request <span class="sy0">=</span> <span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/"><span class="kw5">NSURLRequest</span></a> requestWithURL<span class="sy0">:</span>url<span class="br0">&#93;</span>;
&nbsp;
    UIWebView<span class="sy0">*</span> webView <span class="sy0">=</span> <span class="br0">&#40;</span>UIWebView<span class="sy0">*</span><span class="br0">&#41;</span>self.view;
    <span class="br0">&#91;</span>webView loadRequest<span class="sy0">:</span>request<span class="br0">&#93;</span>;
<span class="br0">&#125;</span></pre>
<p>When the Update button is clicked we perform the update:
<pre class="objc codeblock"><span class="sy0">-</span> <span class="br0">&#40;</span>IBAction<span class="br0">&#41;</span>performUpdate<span class="sy0">:</span><span class="br0">&#40;</span><span class="kw4">id</span><span class="br0">&#41;</span>sender
<span class="br0">&#123;</span>
    SSContentBundle<span class="sy0">*</span> provider <span class="sy0">=</span> <span class="br0">&#91;</span>SSContentBundle mainBundle<span class="br0">&#93;</span>;
&nbsp;
    self.navigationItem.rightBarButtonItem.enabled <span class="sy0">=</span> <span class="kw2">NO</span>;
&nbsp;
    <span class="br0">&#91;</span>provider checkForUpdatesWithCompletionHandler<span class="sy0">:^</span><span class="br0">&#40;</span><span class="kw4">BOOL</span> updateFound, <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/"><span class="kw5">NSError</span></a> <span class="sy0">*</span>error<span class="br0">&#41;</span>
     <span class="br0">&#123;</span>
         self.navigationItem.rightBarButtonItem.enabled <span class="sy0">=</span> <span class="kw2">YES</span>;
&nbsp;
         <span class="kw1">if</span><span class="br0">&#40;</span>error<span class="br0">&#41;</span>
         <span class="br0">&#123;</span>
             NSLog<span class="br0">&#40;</span><span class="co3">@</span><span class="st0">&quot;Error removing old content: %@&quot;</span>, <span class="br0">&#91;</span>error localizedDescription<span class="br0">&#93;</span><span class="br0">&#41;</span>;
             UIAlertView<span class="sy0">*</span> alert;
             alert <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span>UIAlertView alloc<span class="br0">&#93;</span> initWithTitle<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;Content Test&quot;</span>
                                                message<span class="sy0">:</span><span class="br0">&#91;</span>error localizedDescription<span class="br0">&#93;</span>
                                               delegate<span class="sy0">:</span><span class="kw2">nil</span>
                                      cancelButtonTitle<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;OK&quot;</span>
                                      otherButtonTitles<span class="sy0">:</span><span class="kw2">nil</span><span class="br0">&#93;</span>;
             <span class="br0">&#91;</span>alert show<span class="br0">&#93;</span>;
             <span class="br0">&#91;</span>alert release<span class="br0">&#93;</span>;
             <span class="kw1">return</span>;
         <span class="br0">&#125;</span>
&nbsp;
         <span class="kw1">if</span><span class="br0">&#40;</span>updateFound<span class="br0">&#41;</span>
         <span class="br0">&#123;</span>
             <span class="co2">// refresh the browser...</span>
             UIWebView<span class="sy0">*</span> webView <span class="sy0">=</span> <span class="br0">&#40;</span>UIWebView<span class="sy0">*</span><span class="br0">&#41;</span>self.view;
             <span class="br0">&#91;</span>webView reload<span class="br0">&#93;</span>;
         <span class="br0">&#125;</span>
     <span class="br0">&#125;</span><span class="br0">&#93;</span>;
<span class="br0">&#125;</span></pre>
<p>That&#8217;s about it&#8230; The server content has different HTML, and includes an image to prove that we can reference other files &#8211; they&#8217;re all just expanded onto the file system after all.</p>
<p>The changes are already live on github: <a href="https://github.com/ssaxon/contentbundle" target="_blank">https://github.com/ssaxon/contentbundle</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/contentbundle-demo-updated/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>We love you, Grand Rapids, MI</title>
		<link>http://www.stevesaxon.me/posts/2011/we-love-you-grand-rapids-mi/</link>
		<comments>http://www.stevesaxon.me/posts/2011/we-love-you-grand-rapids-mi/#comments</comments>
		<pubDate>Fri, 27 May 2011 16:16:59 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Whacky]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=106</guid>
		<description><![CDATA[What a great rebuttal to being put on Newsweek&#8217;s list of &#8220;dying cities&#8221;&#8230;]]></description>
			<content:encoded><![CDATA[<p>What a great rebuttal to being put on Newsweek&#8217;s list of &#8220;dying cities&#8221;&#8230;</p>
<p><object type="application/x-shockwave-flash" data="http://www.youtube.com/v/ZPjjZCO67WI&#038;hd=1" style="width:620px;height:370px"><param name="wmode" value="opaque"><param name="movie" value="http://www.youtube.com/v/ZPjjZCO67WI&#038;hd=1" /></object></p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/we-love-you-grand-rapids-mi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>window.external.Notify in iOS UIWebView</title>
		<link>http://www.stevesaxon.me/posts/2011/window-external-notify-in-ios-uiwebview/</link>
		<comments>http://www.stevesaxon.me/posts/2011/window-external-notify-in-ios-uiwebview/#comments</comments>
		<pubDate>Fri, 27 May 2011 14:51:12 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[iOS]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=80</guid>
		<description><![CDATA[I recently ran into an interesting problem working on putting support for the Windows Azure Access Control Service (ACS) into the Windows Azure iOS Toolkit. It turns out that once &#8230;]]></description>
			<content:encoded><![CDATA[<p>I recently ran into an interesting problem working on putting support for the Windows Azure Access Control Service (ACS) into the Windows Azure iOS Toolkit.</p>
<p>It turns out that once you&#8217;ve gone through all of the ACS authentication process, a security token is generated. You need this token to authenticate yourself against ACS-bound web sites. However the ACS web site passes the token to you by calling window.external.Notify()
<pre class="javascript codeblock">window.<span class="me1">external</span>.<span class="me1">Notify</span><span class="br0">&#40;</span><span class="st0">&quot;security-token-here&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre>
<p>While window.external.Notify is supported in Internet Explorer on the desktop and also in Windows Phone, it is not supported in iOS. Worse, while the WebView control on the Mac can call your Objective C code from JavaScript, the iOS UIWebView does not support this.</p>
<p>Another mechanism was needed. Here is how I solved it.<span id="more-80"></span><br />
<h3>Extending the JavaScript object model</h3>
<p>The first challenge was how to add in a new method under the built-in window object. What if iOS prevented changes to the window object? Well thankfully it doesn&#8217;t. And because objects in JavaScript are all just dictionaries, it is fairly easy to extend objects at runtime.</p>
<p>The second challenge was how to get information from the JavaScript back to my iOS code, particularly given that we don&#8217;t have access to the Objective C integration we have on the Mac. Actually there is really only one way, and that is by telling the browser to access some URL in a way that we can catch in our UIWebViewDelegate code.</p>
<p>Here is the JavaScript I wrote to extend the window object:
<pre class="javascript codeblock"><span class="sy0">&lt;</span>script type<span class="sy0">=</span>\<span class="st0">&quot;text/javascript<span class="es0">\&quot;</span>&gt;
    window.external =
    {
        'Notify': function(s) { document.location = 'acs://settoken?token=' + s; },
        'notify': function(s) { document.location = 'acs://settoken?token=' + s; }
    };
&lt;/script&gt;</span></pre>
<p>The code above registers the &#8220;external&#8221; property on the window object, and adds two functions. Both uppercase and lowercase versions were required.</p>
<p>I ran into a third problem while trying to hook this JavaScript into the page generated by the ACS web site.</p>
<p>UIWebViewDelegate is fairly simple in what it provides:
<pre class="objc codeblock"><span class="kw1">@protocol</span> UIWebViewDelegate &lt;NSObject&gt;
&nbsp;
@optional
<span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">BOOL</span><span class="br0">&#41;</span>webView<span class="sy0">:</span><span class="br0">&#40;</span>UIWebView <span class="sy0">*</span><span class="br0">&#41;</span>webView
     shouldStartLoadWithRequest<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/"><span class="kw5">NSURLRequest</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>request
                 navigationType<span class="sy0">:</span><span class="br0">&#40;</span>UIWebViewNavigationType<span class="br0">&#41;</span>navigationType;
<span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>webViewDidStartLoad<span class="sy0">:</span><span class="br0">&#40;</span>UIWebView <span class="sy0">*</span><span class="br0">&#41;</span>webView;
<span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>webViewDidFinishLoad<span class="sy0">:</span><span class="br0">&#40;</span>UIWebView <span class="sy0">*</span><span class="br0">&#41;</span>webView;
<span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>webView<span class="sy0">:</span><span class="br0">&#40;</span>UIWebView <span class="sy0">*</span><span class="br0">&#41;</span>webView didFailLoadWithError<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/"><span class="kw5">NSError</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>error;
&nbsp;
<span class="kw1">@end</span></pre>
<p>I seemed like webViewDidFinishLoad: would give me an easy way to integrate this. The problem was that the ACS web site would attempt to call window.external.Notify() immediately after the page loaded, right before my delegate was called. Worse, webViewDidStartLoad: seemed to be too early! I needed to find another way.</p>
<h3>Hooking my script into the UIWebView</h3>
<p>The iOS UIWebView is very simple to use, but that simplicity means there are precious few hooks for doing this type of integration. In fact the only direct way to interact with the page is through the call below:
<pre class="objc codeblock"><span class="sy0">-</span> <span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>stringByEvaluatingJavaScriptFromString<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>script;</pre>
<p>It seemed in theory I could use this call to hook in some JavaScript, but as I mentioned, I couldn&#8217;t get this call in early enough to register it. I needed a more brute-force approach!</p>
<p>My only alternative was webView:shouldStartLoadWithRequest:navigationType:. However, this delegate call is simply telling me that the browser is about to load the content. I would need to load the content myself, prepend my JavaScript (so that it was guaranteed to run before the ACS JavaScript) and give it to the UIWebView.</p>
<p>This was my final version of the delegate call.</p>
<pre class="objc codeblock"><span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">BOOL</span><span class="br0">&#41;</span>webView<span class="sy0">:</span><span class="br0">&#40;</span>UIWebView <span class="sy0">*</span><span class="br0">&#41;</span>webView
     shouldStartLoadWithRequest<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/"><span class="kw5">NSURLRequest</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>request
                 navigationType<span class="sy0">:</span><span class="br0">&#40;</span>UIWebViewNavigationType<span class="br0">&#41;</span>navigationType
<span class="br0">&#123;</span>
    <span class="kw1">if</span><span class="br0">&#40;</span>_url<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="coMULTI">/* make the call re-entrant when we re-load the content ourselves */</span>
        <span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#91;</span>_url isEqual<span class="sy0">:</span><span class="br0">&#91;</span>request URL<span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>
        <span class="br0">&#123;</span>
            <span class="kw1">return</span> <span class="kw2">YES</span>;
        <span class="br0">&#125;</span>
&nbsp;
        <span class="br0">&#91;</span>_url release<span class="br0">&#93;</span>;
    <span class="br0">&#125;</span>
&nbsp;
    _url <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span>request URL<span class="br0">&#93;</span> retain<span class="br0">&#93;</span>;
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> scheme <span class="sy0">=</span> <span class="br0">&#91;</span>_url scheme<span class="br0">&#93;</span>;
&nbsp;
    <span class="kw1">if</span><span class="br0">&#40;</span><span class="br0">&#91;</span>scheme isEqualToString<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;acs&quot;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="co2">// parse the JSON URL parameter into a dictionary</span>
        <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span class="kw5">NSDictionary</span></a><span class="sy0">*</span> pairs <span class="sy0">=</span> <span class="br0">&#91;</span>self parsePairs<span class="sy0">:</span><span class="br0">&#91;</span>_url absoluteString<span class="br0">&#93;</span><span class="br0">&#93;</span>;
        <span class="kw1">if</span><span class="br0">&#40;</span>pairs<span class="br0">&#41;</span>
        <span class="br0">&#123;</span>
            WACloudAccessToken<span class="sy0">*</span> accessToken;
            accessToken <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span>WACloudAccessToken alloc<span class="br0">&#93;</span> initWithDictionary<span class="sy0">:</span>pairs<span class="br0">&#93;</span>;
            <span class="br0">&#91;</span>WACloudAccessControlClient setToken<span class="sy0">:</span>accessToken<span class="br0">&#93;</span>;
&nbsp;
            <span class="br0">&#91;</span>self dismissModalViewControllerAnimated<span class="sy0">:</span><span class="kw2">YES</span><span class="br0">&#93;</span>;
        <span class="br0">&#125;</span>
&nbsp;
        <span class="kw1">return</span> <span class="kw2">NO</span>;
    <span class="br0">&#125;</span>
&nbsp;
    <span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/"><span class="kw5">NSURLConnection</span></a> connectionWithRequest<span class="sy0">:</span>request delegate<span class="sy0">:</span>self<span class="br0">&#93;</span>;
&nbsp;
    <span class="kw1">return</span> <span class="kw2">NO</span>;
<span class="br0">&#125;</span></pre>
<p>You can see this code is really doing 3 things:
<ul>
<li>We remember the URL that was requested. We are going to have to load the HTML ourselves, then give it to UIWebView. When we do that it will call our delegate a second time. We need to recognize that, and treat it like a no-op, or go around in an endless loop.</li>
<li>We need to detect if the URL was our &#8220;acs://&#8221; call made by our JavaScript hook, and if so, take the JSON URL parameter and use it to parse out the security token.</li>
<li>Finally if it is a regular HTML load, we need to begin the process of loading it ourselves and tell UIWebView to not load it by returning NO.</li>
</ul>
<p>I&#8217;m using fairly standard code for my NSURLConnectionDelegate handlers. The only thing out of the ordinary is that once the HTML has finished loading, I prepend the JavaScript we saw earlier and tell the UIWebView to load it.</p>
<pre class="objc codeblock"><span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>connection<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/"><span class="kw5">NSURLConnection</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>connection didFailWithError<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/"><span class="kw5">NSError</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>error
<span class="br0">&#123;</span>
    <span class="kw1">if</span><span class="br0">&#40;</span>_data<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="br0">&#91;</span>_data release<span class="br0">&#93;</span>;
        _data <span class="sy0">=</span> <span class="kw2">nil</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>connection<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/"><span class="kw5">NSURLConnection</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>connection didReceiveData<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/"><span class="kw5">NSData</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>data
<span class="br0">&#123;</span>
    <span class="kw1">if</span><span class="br0">&#40;</span><span class="sy0">!</span>_data<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        _data <span class="sy0">=</span> <span class="br0">&#91;</span>data mutableCopy<span class="br0">&#93;</span>;
    <span class="br0">&#125;</span>
    <span class="kw1">else</span>
    <span class="br0">&#123;</span>
        <span class="br0">&#91;</span>_data appendData<span class="sy0">:</span>data<span class="br0">&#93;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="sy0">-</span> <span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>connectionDidFinishLoading<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/"><span class="kw5">NSURLConnection</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>connection
<span class="br0">&#123;</span>
    <span class="kw1">if</span><span class="br0">&#40;</span>_data<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> content <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a> alloc<span class="br0">&#93;</span> initWithData<span class="sy0">:</span>_data
                                                  encoding<span class="sy0">:</span>NSUTF8StringEncoding<span class="br0">&#93;</span>;
&nbsp;
        <span class="br0">&#91;</span>_data release<span class="br0">&#93;</span>;
        _data <span class="sy0">=</span> <span class="kw2">nil</span>;
&nbsp;
        <span class="co2">// prepend the HTML with our custom JavaScript</span>
        content <span class="sy0">=</span> <span class="br0">&#91;</span>ScriptNotify stringByAppendingString<span class="sy0">:</span>content<span class="br0">&#93;</span>;
&nbsp;
        <span class="br0">&#91;</span>_webView loadHTMLString<span class="sy0">:</span>content baseURL<span class="sy0">:</span>_url<span class="br0">&#93;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre>
<h3>Final thoughts</h3>
<p>While the mechanism shown here may seem a little convoluted, it is solving a fairly specific problem if how to hook into a web page&#8217;s JavaScript early enough to influence what happens.</p>
<p>I&#8217;m curious to know if there is a cleaner way to do this. Let me know.</p>
<p>Finally, here is the code I wrote for converting the ACS security token JSON into a dictionary without using an external JSON parser library such as SBJSON or YAJL. While not as general purpose a third party library, this was good enough for our needs.
<pre class="objc codeblock"><span class="sy0">-</span> <span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span class="kw5">NSDictionary</span></a><span class="sy0">*</span><span class="br0">&#41;</span>parsePairs<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span><span class="br0">&#41;</span>urlStr
<span class="br0">&#123;</span>
    <span class="kw4">NSRange</span> r <span class="sy0">=</span> <span class="br0">&#91;</span>urlStr rangeOfString<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;=&quot;</span><span class="br0">&#93;</span>;
    <span class="kw1">if</span><span class="br0">&#40;</span>r.length <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">return</span> <span class="kw2">nil</span>;
    <span class="br0">&#125;</span>
&nbsp;
    <span class="co2">// the JSON-encoded token is after the = in the URL</span>
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> token <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span>urlStr substringFromIndex<span class="sy0">:</span>r.location <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#93;</span> URLDecode<span class="br0">&#93;</span>;
&nbsp;
    <span class="co2">// remove the leading and trailing { } characters</span>
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSCharacterSet_Class/"><span class="kw5">NSCharacterSet</span></a><span class="sy0">*</span> objectMarkers;
    objectMarkers <span class="sy0">=</span> <span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSCharacterSet_Class/"><span class="kw5">NSCharacterSet</span></a> characterSetWithCharactersInString<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;{}&quot;</span><span class="br0">&#93;</span>;
    token <span class="sy0">=</span> <span class="br0">&#91;</span>token stringByTrimmingCharactersInSet<span class="sy0">:</span>objectMarkers<span class="br0">&#93;</span>;
&nbsp;
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/"><span class="kw5">NSError</span></a><span class="sy0">*</span> regexError;
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSMutableDictionary_Class/"><span class="kw5">NSMutableDictionary</span></a><span class="sy0">*</span> pairs <span class="sy0">=</span> <span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSMutableDictionary_Class/"><span class="kw5">NSMutableDictionary</span></a> dictionaryWithCapacity<span class="sy0">:</span><span class="nu0">10</span><span class="br0">&#93;</span>;
&nbsp;
    <span class="co2">// parse name-value pairs with string values</span>
    NSRegularExpression<span class="sy0">*</span> regex;
    regex <span class="sy0">=</span> <span class="br0">&#91;</span>NSRegularExpression regularExpressionWithPattern<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;<span class="es0">\&quot;</span>([^<span class="es0">\&quot;</span>]*)<span class="es0">\&quot;</span>:<span class="es0">\&quot;</span>([^<span class="es0">\&quot;</span>]*)<span class="es0">\&quot;</span>&quot;</span>
                                                      options<span class="sy0">:</span><span class="nu0">0</span>
                                                        error<span class="sy0">:&amp;</span>regexError<span class="br0">&#93;</span>;
    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/"><span class="kw5">NSArray</span></a><span class="sy0">*</span> matches <span class="sy0">=</span> <span class="br0">&#91;</span>regex matchesInString<span class="sy0">:</span>token
                                      options<span class="sy0">:</span><span class="nu0">0</span>
                                        range<span class="sy0">:</span>NSMakeRange<span class="br0">&#40;</span><span class="nu0">0</span>, token.length<span class="br0">&#41;</span><span class="br0">&#93;</span>;
&nbsp;
    <span class="kw1">for</span><span class="br0">&#40;</span>NSTextCheckingResult<span class="sy0">*</span> result <span class="kw1">in</span> matches<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> n <span class="sy0">=</span> <span class="nu0">1</span>; n &lt; <span class="br0">&#91;</span>result numberOfRanges<span class="br0">&#93;</span>; n <span class="sy0">+=</span> <span class="nu0">2</span><span class="br0">&#41;</span>
        <span class="br0">&#123;</span>
            <span class="kw4">NSRange</span> r <span class="sy0">=</span> <span class="br0">&#91;</span>result rangeAtIndex<span class="sy0">:</span>n<span class="br0">&#93;</span>;
            <span class="kw1">if</span><span class="br0">&#40;</span>r.length &gt; <span class="nu0">0</span><span class="br0">&#41;</span>
            <span class="br0">&#123;</span>
                <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> name <span class="sy0">=</span> <span class="br0">&#91;</span>token substringWithRange<span class="sy0">:</span>r<span class="br0">&#93;</span>;
&nbsp;
                r <span class="sy0">=</span> <span class="br0">&#91;</span>result rangeAtIndex<span class="sy0">:</span>n <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#93;</span>;
                <span class="kw1">if</span><span class="br0">&#40;</span>r.length &gt; <span class="nu0">0</span><span class="br0">&#41;</span>
                <span class="br0">&#123;</span>
                    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> value <span class="sy0">=</span> <span class="br0">&#91;</span>token substringWithRange<span class="sy0">:</span>r<span class="br0">&#93;</span>;
&nbsp;
                    <span class="br0">&#91;</span>pairs setObject<span class="sy0">:</span>value forKey<span class="sy0">:</span>name<span class="br0">&#93;</span>;
                <span class="br0">&#125;</span>
            <span class="br0">&#125;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="co2">// parse name-value pairs with numeric values</span>
    regex <span class="sy0">=</span> <span class="br0">&#91;</span>NSRegularExpression regularExpressionWithPattern<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;<span class="es0">\&quot;</span>([^<span class="es0">\&quot;</span>]*)<span class="es0">\&quot;</span>:([0-9]*)&quot;</span>
                                                      options<span class="sy0">:</span><span class="nu0">0</span>
                                                        error<span class="sy0">:&amp;</span>regexError<span class="br0">&#93;</span>;
    matches <span class="sy0">=</span> <span class="br0">&#91;</span>regex matchesInString<span class="sy0">:</span>token
                              options<span class="sy0">:</span><span class="nu0">0</span>
                                range<span class="sy0">:</span>NSMakeRange<span class="br0">&#40;</span><span class="nu0">0</span>, token.length<span class="br0">&#41;</span><span class="br0">&#93;</span>;
&nbsp;
    <span class="kw1">for</span><span class="br0">&#40;</span>NSTextCheckingResult<span class="sy0">*</span> result <span class="kw1">in</span> matches<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span class="kw1">for</span><span class="br0">&#40;</span><span class="kw4">int</span> n <span class="sy0">=</span> <span class="nu0">1</span>; n &lt; <span class="br0">&#91;</span>result numberOfRanges<span class="br0">&#93;</span>; n <span class="sy0">+=</span> <span class="nu0">2</span><span class="br0">&#41;</span>
        <span class="br0">&#123;</span>
            <span class="kw4">NSRange</span> r <span class="sy0">=</span> <span class="br0">&#91;</span>result rangeAtIndex<span class="sy0">:</span>n<span class="br0">&#93;</span>;
            <span class="kw1">if</span><span class="br0">&#40;</span>r.length &gt; <span class="nu0">0</span><span class="br0">&#41;</span>
            <span class="br0">&#123;</span>
                <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> name <span class="sy0">=</span> <span class="br0">&#91;</span>token substringWithRange<span class="sy0">:</span>r<span class="br0">&#93;</span>;
&nbsp;
                r <span class="sy0">=</span> <span class="br0">&#91;</span>result rangeAtIndex<span class="sy0">:</span>n <span class="sy0">+</span> <span class="nu0">1</span><span class="br0">&#93;</span>;
                <span class="kw1">if</span><span class="br0">&#40;</span>r.length &gt; <span class="nu0">0</span><span class="br0">&#41;</span>
                <span class="br0">&#123;</span>
                    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> value <span class="sy0">=</span> <span class="br0">&#91;</span>token substringWithRange<span class="sy0">:</span>r<span class="br0">&#93;</span>;
                    <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span class="kw5">NSNumber</span></a><span class="sy0">*</span> number <span class="sy0">=</span> <span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/"><span class="kw5">NSNumber</span></a> numberWithInt<span class="sy0">:</span><span class="br0">&#91;</span>value intValue<span class="br0">&#93;</span><span class="br0">&#93;</span>;
&nbsp;
                    <span class="br0">&#91;</span>pairs setObject<span class="sy0">:</span>number forKey<span class="sy0">:</span>name<span class="br0">&#93;</span>;
                <span class="br0">&#125;</span>
            <span class="br0">&#125;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw1">return</span> pairs;
<span class="br0">&#125;</span></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/window-external-notify-in-ios-uiwebview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web updates of content in iOS apps</title>
		<link>http://www.stevesaxon.me/posts/2011/web-updates-of-content-in-ios-apps/</link>
		<comments>http://www.stevesaxon.me/posts/2011/web-updates-of-content-in-ios-apps/#comments</comments>
		<pubDate>Thu, 26 May 2011 22:00:04 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[iOS]]></category>

		<guid isPermaLink="false">http://www.stevesaxon.me/?p=57</guid>
		<description><![CDATA[One common use for mobile apps is to expose a company&#8217;s repertoire of content. Perhaps your app will present cooking recipes, or First Aid information for folks that hurt themselves &#8230;]]></description>
			<content:encoded><![CDATA[<p>One common use for mobile apps is to expose a company&#8217;s repertoire of content.</p>
<p>Perhaps your app will present cooking recipes, or First Aid information for folks that hurt themselves hiking far from cell tower coverage.</p>
<p>One challenge often faced in these types of apps is how to keep the content up to date. Of course you could simply ship an update to your app, but your customers may get annoying having to update your app every few weeks.</p>
<p>A better way is to have a means to update the content as it changes. The code I am presenting here is designed to do just that.<span id="more-57"></span><br />
<h3>Introducing ContentBundle</h3>
<p>The ContentBundle library aims to solve this problem by allowing you to embed content inside your application as a ZIP archive. When the application starts up the first time it will copy the contents of the ZIP file into your application&#8217;s Documents directory. All of the ZIP archive&#8217;s folders structure is pulled over intact, just as you would expect.</p>
<p>Once there you can use any of the built in file APIs to load content in, or even reference it inside of a WebView, which will be able to reference its HTML, CSS and images.</p>
<p>On subsequent startups the application will check its version against the already expanded content version, allowing updates of your application to deploy content updates.</p>
<p>But perhaps more than that, you can have the library reach out to your web site, determine if an update is available, and pull that update down.</p>
<p>To make this work we must first add a section into our application&#8217;s info.plist file:</p>
<p><img src="http://www.stevesaxon.me/wp-content/uploads/2011/05/contentbundle-infoplist.png" alt="Info.plist" /></p>
<p>This section is identifying that our content is in the test.zip file inside our app bundle. It&#8217;s version number is &#8220;1&#8243;. It will be expanded into our Documents folder in a sub-folder called &#8220;mytest&#8221;. Finally we have the URL where the library can obtain updates.</p>
<p>These settings, and the ZIP they references are what I refer to as a &#8220;content bundle&#8221;.</p>
<p>The library allow you to create multiple sections for different content bundles, which may be useful if some of your content will change more frequently than others.</p>
<p>To use the library in your code, first reference the library&#8217;s header file.</p>
<pre class="objc codeblock"><span class="co1">#import &quot;SSContentBundle.h&quot;</span></pre>
<p>To reference content in a content bundle we might first access it.</p>
<p>The default bundle (which leverages the &#8220;SSContentBundle&#8221; key in our info.plist) is accessed via the <b>mainBundle</b> property.</p>
<pre class="objc codeblock">SSContentBundle<span class="sy0">*</span> provider <span class="sy0">=</span> <span class="br0">&#91;</span>SSContentBundle mainBundle<span class="br0">&#93;</span>;</pre>
<p>You can obtain the full path of a file from the bundle thus:</p>
<pre class="objc codeblock"><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a><span class="sy0">*</span> path <span class="sy0">=</span> <span class="br0">&#91;</span>provider pathForFile<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;LiteUnzip.c&quot;</span><span class="br0">&#93;</span>;
<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/"><span class="kw5">NSData</span></a><span class="sy0">*</span> contents <span class="sy0">=</span> <span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/"><span class="kw5">NSData</span></a> dataWithContentsOfFile<span class="sy0">:</span>path<span class="br0">&#93;</span>;</pre>
<h3>Web updates</h3>
<p>At startup if you wish to check for content updates you can call the <b>checkForUpdatesWithCompletionHandler:</b> method.</p>
<pre class="objc codeblock"><span class="br0">&#91;</span>provider checkForUpdatesWithCompletionHandler<span class="sy0">:^</span><span class="br0">&#40;</span><span class="kw4">BOOL</span> updateFound, <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSError_Class/"><span class="kw5">NSError</span></a> <span class="sy0">*</span>error<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span class="kw1">if</span><span class="br0">&#40;</span>error<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        NSLog<span class="br0">&#40;</span><span class="co3">@</span><span class="st0">&quot;Error removing old content: %@&quot;</span>, <span class="br0">&#91;</span>error localizedDescription<span class="br0">&#93;</span><span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span><span class="br0">&#93;</span>;</pre>
<p>The block will be told if an update was found. If it was, the content ZIP file will have been downloaded, expanded and your old content replaced before the completion handler is called.</p>
<p>You may recall the content version URL was defined as:</p>
<p><a href="http://www.stevesaxon.me/media/test/version.txt" target="_blank">http://www.stevesaxon.me/media/test/version.txt</a></p>
<p>This file contains the following:</p>
<pre class="text codeblock">3
test.zip</pre>
<p>The first line is the server version number. Remember our info.plist said our client version was 1, so the server version is newer.</p>
<p>The second line is the relative URL to the server-based content update. In this case, &#8220;test.zip&#8221; is sitting in the same folder on the server as the version.txt file.</p>
<h3>Under the covers</h3>
<p>The TargetFolder key in the info.plist is used to identify the name of the target folder inside your application&#8217;s Documents directory.</p>
<p>It is also to identify the name of the version tracker file that is written by the library so that library knows the version of the content that is stored in the Documents directory. Initially the content of this file is written from the SourceVersion key in the info.plist, but it can be updated as part of a server content fetch.</p>
<p>The Documents directory may end up looking like this:</p>
<p><img src="http://www.stevesaxon.me/wp-content/uploads/2011/05/contentbundle-documents.png" alt="Example documents directory" /></p>
<p>Note the mytest-version.txt, which is the version tracker file. The mytest folder contains the contents of the ZIP file.</p>
<p>When a new content ZIP is downloaded, this folder is deleted and the updated content expanded in its place.</p>
<h3>Getting involved</h3>
<p>The library and sample code is available from github.</p>
<p><a href="https://github.com/ssaxon/ContentBundle" target="_blank">https://github.com/ssaxon/ContentBundle</a></p>
<p>If you this useful, leave a comment. Or jump over to github and get involved!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevesaxon.me/posts/2011/web-updates-of-content-in-ios-apps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

