<?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>A Tasty Pixel » Blog &#187; Cocoa</title>
	<atom:link href="http://atastypixel.com/blog/tag/cocoa/feed/" rel="self" type="application/rss+xml" />
	<link>http://atastypixel.com/blog</link>
	<description></description>
	<lastBuildDate>Wed, 16 May 2012 11:07:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Compiling Image Resources into a Static Library</title>
		<link>http://atastypixel.com/blog/compiling-image-resources-into-a-static-library/</link>
		<comments>http://atastypixel.com/blog/compiling-image-resources-into-a-static-library/#comments</comments>
		<pubDate>Tue, 15 May 2012 20:12:23 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Static Library]]></category>
		<category><![CDATA[XCode]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2523</guid>
		<description><![CDATA[I&#8217;ve recently been working on a static library for distribution to other developers &#8212; Audiobus &#8212; and I need to include a couple of graphical resources with the distribution. The usual solution to this is to include the resources separately in a bundle, and require the user to drop them in to their project along [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently been working on a static library for distribution to other developers &#8212; <a href="http://audiob.us">Audiobus</a> &#8212; and I need to include a couple of graphical resources with the distribution. The usual solution to this is to include the resources separately in a bundle, and require the user to drop them in to their project along with the static library.</p>

<p>I thought I&#8217;d see if I could make the process just a little neater, and successfully devised a way to compile the images straight into the library, so the distribution remains nice and clean &#8212; just the library itself and a few header files.</p>

<p>Now, I can pop image resources into a folder, and after compiling, access them within the static library with:</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">UIImage <span style="color: #002200;">*</span>image <span style="color: #002200;">=</span> TPGetCompiledImage<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Button.png&quot;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>


<p>It automatically handles &#8220;@2x&#8221; Retina images (although it doesn&#8217;t currently do &#8220;~ipad&#8221; versions).</p>

<p>Here&#8217;s how it&#8217;s done.</p>

<p>The magic is in a shell script which uses the <code>xxd</code> hex dump tool to create C code that represents the image data as a byte array, then creates around it a set of utilities to turn those arrays into UIImages on demand.</p>

<p>Along with it is a couple of template files &#8212; a header and implementation file &#8212; that describe the format of the derived code.</p>

<p>Finally, a little tweaking of the project in Xcode (with a brief foray into a text editor to work around some Xcode shortcomings) puts it all together.<span id="more-2523"></span></p>

<p></p>

<p><strong>Update:</strong> Fellow dev Cocoanetics pointed out that they&#8217;d solved a similar problem, and have a great write-up on <a href="http://www.cocoanetics.com/2012/02/xcode-build-rules/">how they create compiled resources using custom build rules</a> on their blog.</p>

<h2>The Image Resources</h2>

<p>…Just a bunch of <code>png</code> files within a folder inside your project directory. The script assumes there are normal and retina (<code>@2x</code>) versions of each.</p>

<h2>The Template</h2>

<p>These are the template source files from which the end result will be derived. It contains a few tags that the accompanying shell script will process. I created it in Xcode, placing it within the same folder as the source png images, but removed it from the target&#8217;s compile phase, as we&#8217;ll be adding the derived source instead.</p>

<p>First the header, <code>TPCompiledResources.h</code>:</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//</span>
<span style="color: #11740a; font-style: italic;">//  TPCompiledResources.h</span>
<span style="color: #11740a; font-style: italic;">//</span>
<span style="color: #11740a; font-style: italic;">//  Created by Michael Tyson on 13/05/2012.</span>
<span style="color: #11740a; font-style: italic;">//  Copyright (c) 2012 A Tasty Pixel. All rights reserved.</span>
<span style="color: #11740a; font-style: italic;">//</span>
&nbsp;
<span style="color: #6e371a;">#import &lt;UIKit/UIKit.h&gt;</span>
&nbsp;
UIImage <span style="color: #002200;">*</span>TPGetCompiledImage<span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span> name<span style="color: #002200;">&#41;</span>;</pre></div></div>


<p>And the implementation file, <code>TPCompiledResources.m</code>:</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//</span>
<span style="color: #11740a; font-style: italic;">//  TPCompiledResources.m</span>
<span style="color: #11740a; font-style: italic;">//</span>
<span style="color: #11740a; font-style: italic;">//  Created by Michael Tyson on 13/05/2012.</span>
<span style="color: #11740a; font-style: italic;">//  Copyright (c) 2012 A Tasty Pixel. All rights reserved.</span>
<span style="color: #11740a; font-style: italic;">//</span>
&nbsp;
<span style="color: #6e371a;">#import &quot;TPCompiledResources.h&quot;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">/*{%IMAGEDATA START%}*/</span>
<span style="color: #11740a; font-style: italic;">/*{%IMAGEDATA END%}*/</span>
&nbsp;
UIImage <span style="color: #002200;">*</span>TPGetCompiledImage<span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span> name<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">/*{%LOAD_TEMPLATE%}
    if ( [name isEqualToString:@&quot;ORIGINAL_FILENAME&quot;] ) {
        static UIImage *_SANITISED_FILENAME_image = nil;
        if ( _SANITISED_FILENAME_image ) return _SANITISED_FILENAME_image;
&nbsp;
        if ( [[UIScreen mainScreen] scale] == 2.0 ) {
            _SANITISED_FILENAME_image = [[UIImage alloc] initWithCGImage:
                                                     [[UIImage imageWithData:[NSData dataWithBytesNoCopy:SANITISED_2X_FILENAME 
                                                                      length:SANITISED_2X_FILENAME_len freeWhenDone:NO]] CGImage] 
                                                                   scale:2.0 
                                                             orientation:UIImageOrientationUp];
        } else {
            _SANITISED_FILENAME_image = [[UIImage alloc] initWithData:[NSData dataWithBytesNoCopy:SANITISED_FILENAME 
                                                                                           length:SANITISED_FILENAME_len freeWhenDone:NO]];
        }
&nbsp;
        return _SANITISED_FILENAME_image;
    }
    {%LOAD_TEMPLATE END%}*/</span>
&nbsp;
    <span style="color: #11740a; font-style: italic;">/*{%IMAGELOADERS START%}*/</span>
    <span style="color: #11740a; font-style: italic;">/*{%IMAGELOADERS END%}*/</span>
    <span style="color: #a61390;">return</span> <span style="color: #a61390;">nil</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>


<h2>The Shell Script</h2>

<p>Here&#8217;s the script that does all the work. The script looks for all &#8220;png&#8221; images in the given folder, then creates C code representing each image along with wrapper code to give access to the image byte arrays, with help from the template.</p>

<p>This script goes into a &#8220;Run Script&#8221; phase, placed at the beginning of the library&#8217;s build process.</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Where the images are (get this from the first &quot;Input Files&quot; entry)</span>
<span style="color: #007800;">RESOURCES_FOLDER</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">dirname</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$SCRIPT_INPUT_FILE_0</span>&quot;</span><span style="color: #000000; font-weight: bold;">`</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># The name of the source template, minus extension</span>
<span style="color: #007800;">SOURCE_NAME</span>=<span style="color: #ff0000;">&quot;TPCompiledResources&quot;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Create C arrays, representing each image</span>
<span style="color: #007800;">tmp</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$TEMP_FILES_DIR</span>/compile-images-$$.tmp&quot;</span>
<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$RESOURCES_FOLDER</span>&quot;</span>
<span style="color: #000000; font-weight: bold;">for</span> image <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">*</span>.png; <span style="color: #000000; font-weight: bold;">do</span>
    xxd <span style="color: #660033;">-i</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$image</span>&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;&gt;</span> <span style="color: #007800;">$tmp</span>.1
<span style="color: #000000; font-weight: bold;">done</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Read the code template</span>
<span style="color: #007800;">TEMPLATE</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">'/{%LOAD_TEMPLATE%}/,/{%LOAD_TEMPLATE END%}/ p'</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$RESOURCES_FOLDER</span>/<span style="color: #007800;">$SOURCE_NAME</span>.m&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #ff0000;">'1 d;$ d'</span><span style="color: #000000; font-weight: bold;">`</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Create loader code for each image</span>
<span style="color: #000000; font-weight: bold;">for</span> image <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #000000; font-weight: bold;">*</span>.png; <span style="color: #000000; font-weight: bold;">do</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$image</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> <span style="color: #660033;">-q</span> <span style="color: #ff0000;">&quot;@2x&quot;</span>; <span style="color: #000000; font-weight: bold;">then</span> <span style="color: #7a0874; font-weight: bold;">continue</span>; <span style="color: #000000; font-weight: bold;">fi</span>
    <span style="color: #007800;">ORIGINAL_FILENAME</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$image</span>&quot;</span>
    <span style="color: #007800;">SANITISED_FILENAME</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$ORIGINAL_FILENAME</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #ff0000;">'s/[^a-zA-Z0-9]/_/g'</span><span style="color: #000000; font-weight: bold;">`</span>
    <span style="color: #007800;">SANITISED_2X_FILENAME</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$SANITISED_FILENAME</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #ff0000;">'s/_png/_2x_png/'</span><span style="color: #000000; font-weight: bold;">`</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$TEMPLATE</span>&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #ff0000;">&quot;s/ORIGINAL_FILENAME/<span style="color: #007800;">$ORIGINAL_FILENAME</span>/g;s/SANITISED_FILENAME/<span style="color: #007800;">$SANITISED_FILENAME</span>/g;s/SANITISED_2X_FILENAME/<span style="color: #007800;">$SANITISED_2X_FILENAME</span>/g&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;&gt;</span> <span style="color: #007800;">$tmp</span>.2
<span style="color: #000000; font-weight: bold;">done</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Create the source file from the template and our generated code</span>
<span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #ff0000;">&quot;/{%IMAGEDATA START%}/ r <span style="color: #007800;">$tmp</span>.1
1,/{%IMAGEDATA START%}/!{/{%IMAGEDATA END%}/,/{%IMAGEDATA START%}/! d;}
/{%IMAGELOADERS START%}/ r <span style="color: #007800;">$tmp</span>.2
1,/{%IMAGELOADERS START%}/!{/{%IMAGELOADERS END%}/,/{%IMAGELOADERS START%]/! d;}&quot;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$RESOURCES_FOLDER</span>/<span style="color: #007800;">$SOURCE_NAME</span>.m&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$DERIVED_FILE_DIR</span>/<span style="color: #007800;">$SOURCE_NAME</span>.m&quot;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Copy the template header file in</span>
<span style="color: #c20cb9; font-weight: bold;">cp</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$RESOURCES_FOLDER</span>/<span style="color: #007800;">$SOURCE_NAME</span>.h&quot;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$DERIVED_FILE_DIR</span>/<span style="color: #007800;">$SOURCE_NAME</span>.h&quot;</span>
&nbsp;
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$tmp</span>.1&quot;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$tmp</span>.2&quot;</span></pre></div></div>


<p>The &#8220;Run Script&#8221; phase that hosts this script also needs a couple of additions, to tell Xcode what the inputs and outputs to the script are: In the &#8220;Input Files&#8221; section, the path to the image resource folder, with a &#8220;<em>&#42;.png</em>&#8221; wildcard at the end, and also the path to those template files, <code>TPCompiledResources.{h,m}</code>. Finally, the two output files go in the &#8220;Output Files&#8221; section:</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" class="aligncenter" src="http://atastypixel.com/blog/wp-content/uploads/2012/05/Screen-Shot-2012-05-15-at-20.42.46.png" alt="Screen Shot 2012 05 15 at 20 42 46" title="Screen Shot 2012-05-15 at 20.42.46.png" border="0" width="400" height="155" /></p>

<h2>Project Setup</h2>

<p>Now it was just a matter of setting up the project to include the derived source files in the build. This was a bit messy and took a little doing, but with guidance from this article by Ben Zado on <a href="http://www.benzado.com/blog/post/352/file-references-relative-to-derived_file_dir-in-xcode">file references relative to DERIVED_FILE_DIR</a>, it wasn&#8217;t too painful:</p>

<ol>
<li>Build, in order to generate the derived source files.</li>
<li>Navigate to the derived sources folder within the build products, and drag the <code>TPCompiledResources.{m,h}</code> into the project, placed within a new group (I called the group &#8220;Derived Sources&#8221;).</li>
<li>The path type for those files (accessible from the properties viewer &#8212; Cmd-I) should be &#8220;Relative to Enclosing Group&#8221;, and consequently the &#8220;Path&#8221; field should just show the filename, with no path component. This was a bit touch-and-go for me, and I had a hard time making this happen, so I left it as-is for now, fixing it manually later in step 8.</li>
<li>Under <em>Xcode Preferences &raquo; Locations &raquo; Source Trees</em>, add an entry with setting name &#8220;<code>DERIVED_FILE_DIR</code>&#8220;, display name &#8220;Derived Files&#8221; and path &#8220;<code>$(DERIVED_FILE_DIR)</code>&#8220;.</li>
<li>Set the path type for the group containing the two derived sources to &#8220;Relative to Derived Files&#8221;.</li>
<li>Quit Xcode, and open the <code>project.pbxproj</code> file from within your project&#8217;s bundle.</li>
<li>Find the &#8220;Derived Sources&#8221; group (or whatever it was named in step 2), and delete the &#8220;path&#8221; property from the list of attributes.</li>
<li>I had to also find the <code>TPCompiledResources.{m,h}</code> file sections and delete the &#8220;path&#8221; attribute for those, too.</li>
<li>Reopen Xcode, and build &#8212; it should be good to go (don&#8217;t worry that the derived sources are shown in red in the project group &#8212; Xcode&#8217;ll find them).</li>
</ol>

<p>Now that&#8217;s done, images can be accessed by <code>TPGetCompiledImage(@"ImageName.png")</code>. Yay!</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2523" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/compiling-image-resources-into-a-static-library/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Avoiding duplicate symbol issues when using common utilities within a static library</title>
		<link>http://atastypixel.com/blog/avoiding-duplicate-symbol-issues-when-using-common-utilities-within-a-static-library/</link>
		<comments>http://atastypixel.com/blog/avoiding-duplicate-symbol-issues-when-using-common-utilities-within-a-static-library/#comments</comments>
		<pubDate>Sun, 15 Apr 2012 12:04:44 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Static Libraries]]></category>
		<category><![CDATA[XCode]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2503</guid>
		<description><![CDATA[I&#8217;m working on two projects right now that have static library products, to be given to other developers to use in their projects: Audiobus and The Amazing Audio Engine. In both cases, I&#8217;m making quite heavy use of my circular buffer code, TPCircularBuffer, which would result in duplicate symbol errors if the static library were [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://atastypixel.com/blog/wp-content/uploads/2012/04/Screen-Shot-2012-04-15-at-14.03.28.png" alt="Screen Shot 2012 04 15 at 14 03 28" title="Screen Shot 2012-04-15 at 14.03.28.png" border="0" width="355" height="215" style="float:right;" class="alignright" />I&#8217;m working on two projects right now that have static library products, to be given to other developers to use in their projects: <a href="http://audiob.us">Audiobus</a> and <a href="http://theamazingaudioengine.com">The Amazing Audio Engine</a>. In both cases, I&#8217;m making quite heavy use of my circular buffer code, <a href="http://github.com/michaeltyson/TPCircularBuffer">TPCircularBuffer</a>, which would result in duplicate symbol errors if the static library were linked with another project that used it.</p>

<p>In case the solution was useful to others, here&#8217;s how I worked around it: Use the preprocessor to rename the symbols automatically during the build phase.</p>

<p>This is done by adding a series of <code>-DOldSymbol=NewSymbol</code> flags to the &#8216;Other C Flags&#8217; build setting &#8211; like <code>-DTPCircularBuffer=ABCircularBuffer</code>, for instance.</p>

<p>No more symbol conflicts.</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2503" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/avoiding-duplicate-symbol-issues-when-using-common-utilities-within-a-static-library/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>An Xcode 4 template to create universal static libraries</title>
		<link>http://atastypixel.com/blog/an-xcode-4-template-to-create-universal-static-libraries/</link>
		<comments>http://atastypixel.com/blog/an-xcode-4-template-to-create-universal-static-libraries/#comments</comments>
		<pubDate>Thu, 29 Mar 2012 16:00:02 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Static Libraries]]></category>
		<category><![CDATA[Utility]]></category>
		<category><![CDATA[XCode]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2497</guid>
		<description><![CDATA[I&#8217;ve created an Xcode 4 project template to create universal (armv6, armv7 and simulator) static libraries for iOS, based on Adam Martin&#8217;s script: iOS-Universal-Library-Template The existing static library template provided with Xcode only builds one architecture, which is not particularly suitable for distribution. A number of people have created scripts to create universal libraries, which [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve created an Xcode 4 project template to create universal (armv6, armv7 and simulator) static libraries for iOS, based on <a href="http://red-glasses.com/index.php/tutorials/xcode4-make-a-library-in-one-file-that-works-on-both-device-and-simulator/comment-page-1/#comment-2226">Adam Martin&#8217;s script</a>:</p>

<p><a href="https://github.com/michaeltyson/iOS-Universal-Library-Template">iOS-Universal-Library-Template</a></p>

<p>The existing static library template provided with Xcode only builds one architecture, which is not particularly suitable for distribution. A number of people have created scripts to create universal libraries, which require some mucking around with Xcode target settings to use.</p>

<p>This template draws on this work to provide all that is required to produce universal libraries &#8211; just select the &#8216;Universal Static Library&#8217; type in the New Project/New Target dialog, and you&#8217;re all set.</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" class="aligncenter" src="http://atastypixel.com/blog/wp-content/uploads/2012/03/universal-static-library.jpg" alt="Universal static library" title="universal-static-library.jpg" border="0" width="450" height="305" /></p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2497" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/an-xcode-4-template-to-create-universal-static-libraries/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Uploading to TestFlight with a few keystrokes, using Alfred</title>
		<link>http://atastypixel.com/blog/uploading-to-testflight-with-a-few-keystrokes-using-alfred/</link>
		<comments>http://atastypixel.com/blog/uploading-to-testflight-with-a-few-keystrokes-using-alfred/#comments</comments>
		<pubDate>Thu, 22 Mar 2012 21:11:02 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Alfred]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Scripts]]></category>
		<category><![CDATA[TestFlight]]></category>
		<category><![CDATA[Utility]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2493</guid>
		<description><![CDATA[Here&#8217;s a cute little Alfred extension I put together today that uploads a file to a TestFlight team for you, after prompting for build notes. You&#8217;ll wanna edit the extension to put in your API key and Team ID, then just select a file in Alfred, type &#8216;testflight&#8217; (or an abbreviation thereof) and enter, then [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://atastypixel.com/blog/wp-content/uploads/2012/03/TestFlight-Icon.png" alt="TestFlight Icon" title="TestFlight Icon.png" border="0" width="100" height="100" style="float:right;" class="alignright" />Here&#8217;s a cute little Alfred extension I put together today that uploads a file to a TestFlight team for you, after prompting for build notes.</p>

<p>You&#8217;ll wanna edit the extension to put in your API key and Team ID, then just select a file in Alfred, type &#8216;testflight&#8217; (or an abbreviation thereof) and enter, then enter a build summary, and off it goes. Result will appear in Growl.</p>

<p><a href="http://atastypixel.com/blog/wp-content/uploads/2012/03/Upload-to-TestFlight.alfredextension.zip" title="Upload to TestFlight.alfredextension.zip" alt="Upload to TestFlight alfredextension">Upload to TestFlight.alfredextension.zip</a></p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" class="aligncenter" src="http://atastypixel.com/blog/wp-content/uploads/2012/03/Screen-Shot-2012-03-22-at-22.10.00.png" alt="Screen Shot 2012 03 22 at 22 10 00" title="Screen Shot 2012-03-22 at 22.10.00.png" border="0" width="500" height="317" /></p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2493" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/uploading-to-testflight-with-a-few-keystrokes-using-alfred/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Amazing Audio Engine: Funky Remote IO-based Core Audio Engine Coming Soon</title>
		<link>http://atastypixel.com/blog/the-amazing-audio-engine-funky-remote-io-based-core-audio-engine-coming-soon/</link>
		<comments>http://atastypixel.com/blog/the-amazing-audio-engine-funky-remote-io-based-core-audio-engine-coming-soon/#comments</comments>
		<pubDate>Sat, 17 Mar 2012 22:14:38 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Products]]></category>
		<category><![CDATA[Announcement]]></category>
		<category><![CDATA[Audio]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[iOS]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2486</guid>
		<description><![CDATA[Huzzah! I&#8217;m announcing a new project which will be launching over the next couple of months. It&#8217;s called The Amazing Audio Engine, and it represents the product of years of experience with iOS audio. It&#8217;s a sophisticated iOS audio engine that lets developers skip the Core Audio learning curve, and get on with writing great [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://theamazingaudioengine.com"><img src="http://atastypixel.com/blog/wp-content/uploads/2012/03/amazingaudioengine.jpg" alt="The Amazing Audio Engine" title="amazingaudioengine.jpg" border="0" width="400" height="266" style="float:right; margin-left: 10px; margin-bottom: 10px;" class="alignright" /></a>Huzzah! I&#8217;m announcing a new project which will be launching over the next couple of months.</p>

<p>It&#8217;s called <a href="http://theamazingaudioengine.com">The Amazing Audio Engine</a>, and it represents the product of years of experience with iOS audio. It&#8217;s a sophisticated iOS audio engine that lets developers skip the Core Audio learning curve, and get on with writing great software.</p>

<p>The tech behind this is what drives <a href="http://loopyapp.com">Loopy and Loopy HD</a>, as well as the in-development <a href="http://audiob.us">Audiobus</a> app.</p>

<p><a href="http://theamazingaudioengine.com">Subscribe at theamazingaudioengine.com</a> to be kept in the loop as it approaches launch time.</p>

<p>Some of the features:</p>

<ul>
<li>Automatic mixing of multiple audio signals with per-channel volume and pan controls.</li>
<li>Built-in support for audio filtering and effects, including the ability to form complex filter chains, constructing channel groups, or even whole trees of groups, and filtering them as one composite signal.</li>
<li>Built-in support for audio input, including optional use of the Voice Processing IO unit, for automatic echo removal &#8211; great for VoIP.</li>
<li>Record or monitor the output of the whole audio system, for in-app session recording, or get the output of one channel, or any group of channels in the processing tree.</li>
<li>Support for any audio format (AudioStreamBasicDescription) that the hardware supports: Interleaved, non-interleaved, mono, stereo, 44.1kHz or any other supported sample rate, 16-bit, 8.24 fixed floating-point &#8211; whatever you need for your project.</li>
<li>Very light, efficient engine, designed from the ground up for speed. All Core Audio code is pure C; no Objective-   C or BSD calls, no locks, no memory allocation.</li>
<li>Efficient mixing of input signals, using Apple&#8217;s MultiChannelMixer.</li>
<li>Fast, lock-free synchronisation mechanism, enabling developers to send messages to the main thread from the Core Audio context, and vice versa, without
        locking or memory allocation from the Core Audio thread.  Message sending from the main thread is two-way, and can be asynchronous, with a response
        block, or synchronous.</li>
</ul>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2486" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/the-amazing-audio-engine-funky-remote-io-based-core-audio-engine-coming-soon/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Some updates to TPCircularBuffer</title>
		<link>http://atastypixel.com/blog/some-updates-to-tpcircularbuffer/</link>
		<comments>http://atastypixel.com/blog/some-updates-to-tpcircularbuffer/#comments</comments>
		<pubDate>Tue, 14 Feb 2012 10:28:09 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Audio]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Optimisation]]></category>
		<category><![CDATA[Update]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2450</guid>
		<description><![CDATA[I&#8217;ve recently made some updates to TPCircularBuffer (on GitHub), my C circular/ring buffer implementation, which add a memory barrier on read and write, inline the main functions for a potential performance boost, and add support for use within C++ projects. If you&#8217;re using TPCircularBuffer at all, I recommend updating!]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently made some updates to <a href="http://atastypixel.com/blog/circular-ring-buffer-plus-neat-virtual-memory-mapping-trick/">TPCircularBuffer</a> (<a href="https://github.com/michaeltyson/TPCircularBuffer">on GitHub</a>), my C circular/ring buffer implementation, which add a memory barrier on read and write, inline the main functions for a potential performance boost, and add support for use within C++ projects.</p>

<p>If you&#8217;re using TPCircularBuffer at all, I recommend updating!</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2450" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/some-updates-to-tpcircularbuffer/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Circular (ring) buffer plus neat virtual memory mapping trick</title>
		<link>http://atastypixel.com/blog/circular-ring-buffer-plus-neat-virtual-memory-mapping-trick/</link>
		<comments>http://atastypixel.com/blog/circular-ring-buffer-plus-neat-virtual-memory-mapping-trick/#comments</comments>
		<pubDate>Sat, 10 Dec 2011 13:13:20 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Audio]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Optimisation]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2370</guid>
		<description><![CDATA[I&#8217;ve just updated my C circular buffer implementation, adopting the trick originally proposed by Philip Howard and adapted to Darwin by Kurt Revis: A virtual copy of the buffer is inserted directly after the end of the buffer, so that you can write past the end of the buffer, but have your writes automatically wrapped [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just updated my <a href="http://atastypixel.com/blog/a-simple-fast-circular-buffer-implementation-for-audio-processing/">C circular buffer implementation</a>, adopting the trick originally proposed by <a href="http://vrb.slashusr.org/">Philip Howard</a> and <a href="http://www.snoize.com/Code/PlayBufferedSoundFile.tar.gz">adapted to Darwin</a> by <a href="http://www.snoize.com">Kurt Revis</a>: A virtual copy of the buffer is inserted directly after the end of the buffer, so that you can write past the end of the buffer, but have your writes automatically wrapped around to the start &#8212; no need to manually implement buffer wrapping logic.</p>

<p>This dramatically simplifies the use of a circular buffer &#8212; you can use chunks of the buffer without any need to worry about where the wrap point is.</p>

<p>See the new implementation, which is thread-safe with one consumer and one producer, with no need for locks, making it perfect for use with high-priority Core Audio threads, on <a href="https://github.com/michaeltyson/TPCircularBuffer">GitHub: TPCircularBuffer</a>.</p>

<p>There&#8217;s a basic example of its use over on the <a href="http://atastypixel.com/blog/a-simple-fast-circular-buffer-implementation-for-audio-processing/">original post</a>.</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2370" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/circular-ring-buffer-plus-neat-virtual-memory-mapping-trick/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Experiences with some app promotion strategies</title>
		<link>http://atastypixel.com/blog/experiences-with-some-app-promotion-strategies/</link>
		<comments>http://atastypixel.com/blog/experiences-with-some-app-promotion-strategies/#comments</comments>
		<pubDate>Fri, 07 Oct 2011 17:09:37 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Advertising]]></category>
		<category><![CDATA[App Store]]></category>
		<category><![CDATA[Apps]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Marketing]]></category>
		<category><![CDATA[PR]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2327</guid>
		<description><![CDATA[In the dim and distant past, while in a moment of neglecting my PhD to work on the very first version of Loopy (which is now currently one of the most popular music apps on the iPad!), I had grand visions of an almost totally passive income, making apps. I love the creative initial product [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://atastypixel.com/blog/wp-content/uploads/2011/10/buy-my-thing.jpg" alt="Buy my thing" title="buy-my-thing.jpg" border="0" width="240" height="240" style="float:right;" class="alignright" />In the dim and distant past, while in a moment of neglecting my PhD to work on the very first version of <a href="http://loopyapp.com">Loopy</a> (which is now currently one of the most popular music apps on the iPad!), I had grand visions of an almost totally passive income, making apps.  I love the creative initial product development process and, with naive optimism, I pictured pumping apps out and then sitting back and watching the money roll on in.  Tim Ferriss&#8217;s <a href="http://www.fourhourworkweek.com/">4-Hour Workweek</a> had me enthusiastically lifestyle-designing and dreaming of all my free moneys.</p>

<p>I bet I&#8217;m not the only one, but of course reality struck and we realised that the App Store aint that kind of beast. Like any other product, an app needs to be actively presented to the world on a regular basis, and needs to be nurtured to keep it fresh and relevant.</p>

<p>I say &#8220;we&#8221; because at this point, my partner <a href="http://nelliewindmill.com">Katherine</a> joined me after this particular revelation, and became A Tasty Pixel&#8217;s part-time marketing director and PR strategist &#8212; it&#8217;s taken two of us to keep A Tasty Pixel&#8217;s wheels turning smoothly, and we still have a <em>lot</em> to learn.</p>

<p>I thought I&#8217;d take a moment to reflect on some of the lessons we&#8217;ve learned in the past year, in which we&#8217;ve released a relatively successful travel planning and travel assistant app, <a href="http://cartographer-app.com">The Cartographer</a>, a very successful live looping app, <a href="http://loopyapp.com">Loopy</a>, and its big brother <a href="http://loopyapp.com">Loopy HD</a>, and tried a bunch of promotion strategies, some successful, some not, and some that haven&#8217;t yet run their course.<span id="more-2327"></span></p>

<h3>Stating the obvious: It&#8217;s not enough to just build it</h3>

<p>Just for the record, and I&#8217;m sure we all know this now, but &#8220;build it and they will come&#8221; doesn&#8217;t cut it on the App Store.  Maybe it did in Month One, but now, you might as well not start if you&#8217;re not going to devote a goodly amount of time to promoting your app, because it just won&#8217;t get anywhere amongst the hoards of other apps.</p>

<h3>Don&#8217;t expect everything to work</h3>

<p>Perhaps the biggest, or at least most helpful, lesson we learned was not to expect everything to go as planned, and not to get too down if a strategy didn&#8217;t pan out.</p>

<p>It&#8217;s often impossible to predict which things will be successful and which not, but we found it helpful to consider the payoff for the successful strategies being spread around amongst all the strategies, successful or not &#8212; that way, we could be pleased about the ones that paid off, and philosophical about the ones that didn&#8217;t!  The trick is just to keep at it, and keep being creative.</p>

<h3>High quality attracts attention</h3>

<p>Please excuse a moment of immodesty: I&#8217;d like to think my apps have a fairly high standard of quality, and it would appear that making &#8220;premium&#8221; apps really does pay off!</p>

<p>It&#8217;s not entirely &#8220;build it and they will come&#8221;, but having an app that looks great and that customers love gives you a big head-start in the PR game.  Word of mouth is huge on the App Store, and the mouths in question produce more words about great apps.</p>

<p>What&#8217;s more, a feature by Apple, which generally only happens to high-quality apps, can make a massive difference, both in the short and long term, and gives an app a great &#8220;social proof&#8221; bump.</p>

<p>Incidentally, this goes for the app site too. Sites like <a href="http://appsites.com">App Sites</a> reward beautiful designs, and you can get picked up on various design blogs too &#8212; we&#8217;ve had quite a bit of traffic lately from <a href="http://www.blogduwebdesign.com/webdesign-inspiration/20-webdesign-efficaces-pour-presenter-une-application-mobile/522">Blog Du Webdesign</a>, for example.  And the same goes for demo videos. The Cartographer&#8217;s demo got a huge response, and got a lot of word of mouth, <em>just about the video itself</em>:</p>

<iframe width="539" height="274" src="http://www.youtube.com/embed/H1CbO1zgNXY?rel=0" frameborder="0" allowfullscreen></iframe>

<p>So: Put in the extra sweat-and-tears. It&#8217;s worth it.</p>

<h3>Influencers</h3>

<p>Sometimes, depending on the nature of the app, a good word from an influencer in the area can be huge.</p>

<p>For example, when Loopy was in pre-release, I made contact with a musician I&#8217;m a big fan of, <a href="http://dubfx.net">Dub Fx</a> (you might know him from <a href="http://www.youtube.com/watch?v=8F6EoMdn95E">this video</a>, which went viral a couple of years ago). Ben was very interested in the app, and threw his not inconsiderable support behind it, unleashing this amazing demo video:</p>

<iframe width="539" height="274" src="http://www.youtube.com/embed/7GgiVhTB_yA?rel=0" frameborder="0" allowfullscreen></iframe>

<p>…our jaws were dangling around our knees when I found that in my inbox!  We&#8217;ve since decided to work together &#8212; look out for the Dub Fx app some time next year!</p>

<p>That was the success story &#8212; our experience with The Cartographer was quite different, though. Katherine spent months upon months getting to know travel bloggers, interacting on their blogs and via various social media, hoping to make connections and get to introduce the app to some of them.</p>

<p>The good news is that we made some really good new friends out of the process, which makes it all worthwhile as far as I&#8217;m concerned.  But as a marketing strategy, it was a total bust. As it turns out, many travel bloggers seem to be  quite unresponsive &#8212; some of them, despite lots of friendly comments and other interactions, never even noticed us!  Some did, and kindly give us a mention on their blogs, but this didn&#8217;t seem to have any effect!</p>

<p>It turns out, as Katherine discovered in an industry report, the places that travellers (our target audience) go on the Internet: Not travel blogs!  Travellers visit airline sites, hotel websites, TripAdvisor and forums, Lonely Planet&#8217;s forums…all places that we have no hope of exerting any influence at all (those forums, by the way, are <em>militantly</em> moderated for anything that even loosely resembles product mentions).  So, we did the best we could, given the options, but it&#8217;s a really difficult market.</p>

<p>So, I suppose the lesson there is tread carefully, do your research, and spend the time strategically &#8212; be aware that the payoff might be huge, or it might be nil.  If we&#8217;d known in advance how poorly the months of work Katherine put into meeting travel bloggers would turn out, we might have invested less time in it.  We may have even decided to find an alternative target market.</p>

<h3>Reviewers</h3>

<p>There are a <em>lot</em> of app review sites out there, now. It&#8217;s just insane &#8212; it seems like every man, his dog, and several of his goldfish have app review blogs.  Back at the start, Katherine put in a huge number of hours and built us a spreadsheet of the most important reviewers.  With that done, whenever we do a release, she spends half a day (that&#8217;s how long it takes, or more!) emailing and filling out web forms of reviewers.</p>

<p>Most of them never respond, especially the big ones &#8212; they get such a barrage of review requests, it&#8217;s not hugely surprising.  Many blogs offer paid reviews, but we haven&#8217;t gone down that track yet, so, nothing to report there.  But many have responded, and every review helps, both for the social proof and word-of-mouth, and for the SEO.</p>

<p>Honestly, we haven&#8217;t yet collected hard stats about the proportion of reviewers who contact us in response to our initial contact, and how many are contacting us of their own accord.  Many of the significant reviews we&#8217;ve had have happened independently of us tracking down and contacting the reviewers in question, though.</p>

<p>So, we&#8217;re still undecided about whether the amount of time invested in telling reviewers about our products is really paying off.  I think we&#8217;ll always do it for initial releases, and possibly for major, major updates, though.</p>

<h3>Journalists</h3>

<p>This is something we want to do, but haven&#8217;t really pursued a whole lot &#8212; finding relevant journalists and contacting them directly.  We&#8217;ve found contacts for a few, but they always seem to be out-of-date and emails just bounce.</p>

<p>So, this seems like a good thing to do, but still TBD.</p>

<h3>Press releases</h3>

<p>Press releases seem to have two main benefits &#8212; they help with SEO, which helps users find your app &#8212; and they marginally increase the likelihood of getting picked up and getting some free media.</p>

<p>We&#8217;ve been doing regular monthly <a href="http://www.prweb.com/releases/2011/10/prweb8853583.htm">press releases</a> via PRWeb (a.k.a. Vocus) for a few months now, after previously only doing a big one (via PRWeb) for launch, and a couple smaller ones (via the much cheaper PRMac service) for updates.</p>

<p>Vocus talked us into signing up for a 12 month subscription (for a thousand-and-something $), which includes one release a month, and a representative who helps suggest topics, and checks over our drafts.  Our representative Rebecca has been great with both, and has been very responsive with answering our dumb questions along the way.</p>

<p>We&#8217;ve been <a href="http://www.sfgate.com/cgi-bin/article.cgi?f=/g/a/2011/10/06/prweb8853583.DTL">pseudo-picked up</a> by a few nice sites like the San Francisco Chronicle, although it&#8217;s automated and I don&#8217;t know how much of a direct difference it actually makes.  At the moment, loopyapp.com&#8217;s page rank is at 4, which is not bad at all, some of which is presumably thanks to our releases, and we seem to rank fairly well with most of the google searches we want to be associated with.  An interesting side note is that quite a lot of our referred web traffic is coming straight from PRWeb, which surprised me.</p>

<p>As with a lot of these strategies, I can&#8217;t say for sure whether it&#8217;s been a huge success so far &#8212; it&#8217;s hard to determine the cause of a good page rank, for example &#8212; but my gut feeling is that it&#8217;s worthwhile; it makes sense.</p>

<h3>Social media</h3>

<p>I never &#8220;got&#8221; Facebook up until quite recently, but now I can&#8217;t get enough &#8212; after being a staunch Twitter user for quite a long time, I&#8217;ve discovered that Facebookers are amazingly engaged.  I remember hearing somewhere that one Facebook follower (…&#8221;like&#8221;-r?) is worth several Twitter followers, and that rings true. I have a great time hanging around on the <a href="http://facebook.com/ATastyPixel">A Tasty Pixel Facebook page</a> and interacting with people there, as opposed to Twitter, which is sometimes a little bit like shouting into a black hole.</p>

<p>Google+? I have no bleeding idea. Anyone?</p>

<p>Anyway, it&#8217;s important to engage with your customers on both, but particularly Facebook, and there&#8217;s lots of scope for interesting interactions with customers.  For example, I&#8217;m about to start building effects into Loopy, and I was curious about what people most wanted to see.  So, I created a <a href="http://www.facebook.com/home.php?sk=question&amp;id=219136051461469&amp;qa_ref=qd">poll</a> on the Facebook page, and got a great response (&#8220;More Cowbell&#8221; coming right up…).</p>

<p>I quite like being able to &#8220;be me&#8221; on Twitter and Facebook, to show what I&#8217;m up to, get feedback on stuff as I&#8217;m making it, and to respond straight away to people.  I get to present a personal face, instead of being A Company.</p>

<p>As Loopy is a music-creation app, it also hooks straight into SoundCloud, and has a very active <a href="http://soundcloud.com/groups/loopyapp">SoundCloud group</a> which I find myself trawling every morning &#8212; a great entertainment.  One of the unexpected benefits is that I&#8217;ve met quite a few talented and lovely people though SoundCloud, some of whom have gone on to become testers and advisors, and help shape Loopy.</p>

<h3>Customer support</h3>

<p>While this isn&#8217;t promotion-related, I&#8217;ve been in the position (being a one-person dev company) to interact with customers directly, and I make a point of responding almost immediately when possible, and doing my best to address problems straight away. On a couple of occasions, the customer&#8217;s helped me identify a time-sensitive issue &#8212; they&#8217;re using The Cartographer and are about to go away on holiday &#8212; and I&#8217;ve had a fixed ad-hoc build out to them within a couple of hours, which has been very satisfying on both sides!</p>

<p>Customers love the straight-to-developer contact and the fast replies, and quite a few people have gone on to become very vocal supporters, which has been great. A very positive support experience goes a long way towards building goodwill, and I think it&#8217;s super-important. It also feels really satisfying, so in my option, there&#8217;s no reason not to go all-out!</p>

<h3>Expertise</h3>

<p><a href="http://www.fourhourworkweek.com/">Tim Ferriss</a> encourages product creators to position themselves as authorities in the area targeted by the product, to give the product more clout and attract more attention.  The idea is, if your app is targeted at a particular area, and you have experience in that area, then write: write on your own blog, and seek out others to do guest posts on (make sure it links back to you!).</p>

<p>We&#8217;re spending a few years travelling in a motorhome around Europe as we set up A Tasty Pixel and Katherine&#8217;s art business, and The Cartographer was built as a result of our experiences travelling.  So, (I say &#8220;so&#8221;, but actually we were already blogging as a journal for ourselves &#8212; but let us conveniently ignore that fact) we keep a <a href="http://technomadics.net">travel blog</a>, which brings in some traffic.  But not much &#8212; honestly, this is a terrible example, and we&#8217;ve had very few results, possibly because of the nature (and diminutive size!) of our audience.  Were we to focus on promoting our blog more and making it less &#8220;this-is-what-we-did&#8221; and more &#8220;this-is-what-you-can-do&#8221;, we might see more response, but our priorities lie decidedly elsewhere &#8212; traditional travel blogging: not our bag, baby.</p>

<p>But, I know this can work &#8212; I know it&#8217;s an extreme example, but look at <a href="http://www.stuckincustoms.com/">Trey Ratcliff</a>, the HDR photography authority, and his app <a href="http://www.100camerasin1.com/">100 Cameras In 1</a>. They got onto CNN, ferchrissake, and pretty much every other media outlet you can imagine!</p>

<h3>Paid advertising</h3>

<p>This is the next frontier, for us, and I&#8217;m fairly excited about it.  Everything I&#8217;ve mentioned up to this point has been about &#8220;free media&#8221;, but advertising is a whole new category to explore.</p>

<p>With that said, I&#8217;ve had two initial forays into ads: Facebook, and AdMob, and both have been total failures.</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" class="aligncenter" src="http://atastypixel.com/blog/wp-content/uploads/2011/10/Screen-Shot-2011-10-07-at-16.55.38.png" alt="Facebook ads" title="Screen Shot 2011-10-07 at 16.55.38.png" border="0" width="540" height="141" /></p>

<p>To an advertiser, Facebook is like a giant damn candy shop. (I felt really weird when I read <a href="http://www.geekculture.com/joyoftech/joyarchives/1594.html">this recent Joy of Tech</a>, and found myself drooling a little bit by the fifth panel…).  The kind of targeting options available are just a-mazing &#8212; you can target people from their age, gender and location, right down to their areas of interest (which is insanely cool), and even down to targeting users who like one particular competitor&#8217;s product.</p>

<p>Despite the cool factor, it turned out to be pretty much a total bust for attempt 1 &#8212; we were paying a stupid amount per click, compared to the actual amount we would earn per sale.  We spent $75, and got…45 clicks.  That&#8217;s $1.60 per click, which represents about 75% of our actual take per sale, and it&#8217;s very unlikely even 10% of those clicks resulted in a sale.</p>

<p>At the time, I was choosing to bid per thousand clicks (CPM), instead of per click (CPC), but the reason I chose to was that the recommended CPC was well above what I was prepared to spend.</p>

<p><img src="http://atastypixel.com/blog/wp-content/uploads/2011/10/Screen-Shot-2011-10-07-at-17.03.36.png" alt="AdMob summary" title="AdMob summary" border="0" width="147" height="300" style="float:right; margin-left: 20px;" class="alignright" />The lesson there is that Facebook users aren&#8217;t ready to buy straight away. A friend who works in advertising reported good results marketing the <em>Facebook page</em> instead of the product, so that users who are interested can hang around for a while, get to know you, and then you can market to them later.  I&#8217;ll try this soon, and I&#8217;m hoping that the mechanics of a social ad (with a &#8220;Like&#8221; button on the ad, instead of a click to navigate away from the current page) will result in higher (and cheaper!) conversions.</p>

<p>I found similar results with AdMob &#8212; we got a much, much better cost per click (I was playing with the minimum bid of 29c per click), but even at 29c/click, in order to break even for our $2.99 app, 1 in 7 people who click the ad would have to buy it, which I think is far-fetched.</p>

<p>So, as far as direct advertising goes: As someone who earns just over $2 per sale, we just can&#8217;t afford it!  My next experiment: Trying to use Facebook to increase our social reach, instead.</p>

<h3>Summary</h3>

<p>It&#8217;s become abundantly clear to us that app promotion is a job in itself, and it&#8217;s one that can scale right up to the amount of time you have available.  They key is to be constantly creative, and to be out there, all the time, chipping away.</p>

<p>Almost everything&#8217;s a shot in the dark, and while many strategies may yield no results at all, some might be a big break (like meeting Dub Fx, for us), so it&#8217;s important to just keep on trying.</p>

<p>Apple give you absolutely no help in tracking the success of any particular strategy, unfortunately, although there are <a href="http://atastypixel.com/blog/automatically-track-app-sale-referrals/">tricks you can use</a> to help track where some of your sales are coming from.</p>

<p>The PR thing is just as important as actually creating the app; it&#8217;s hard, and it&#8217;s constant, and it means that running a software development company is anything but a &#8220;passive income&#8221;.  Fortunately for me, I love it to bits!</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2327" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/experiences-with-some-app-promotion-strategies/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Automatically Track App Sale Referrals</title>
		<link>http://atastypixel.com/blog/automatically-track-app-sale-referrals/</link>
		<comments>http://atastypixel.com/blog/automatically-track-app-sale-referrals/#comments</comments>
		<pubDate>Tue, 13 Sep 2011 11:40:56 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[App Store]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Stats]]></category>
		<category><![CDATA[Tracking]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2275</guid>
		<description><![CDATA[I recently came across an article on Mobile Orchard about connecting click-throughs to app sales, which is a rather ingenious idea using the affiliate program LinkShare to create trackable links. As Apple record and report orders that come via these referral links, you can actually see the number of sales (not just views of the [...]]]></description>
			<content:encoded><![CDATA[<p>I recently came across an article on Mobile Orchard about <a href="http://mobileorchard.com/connecting-click-throughs-to-app-sales/">connecting click-throughs to app sales</a>, which is a rather ingenious idea using the affiliate program <a href="http://linkshare.com">LinkShare</a> to create trackable links.  As Apple record and report orders that come via these referral links, you can actually see the number of sales (not just views of the App Store page) that resulted from follows of the link. Plus you get a 5% cut of the sale!</p>

<p>I&#8217;m doing some experiments with advertising my live looper app <a href="http://loopyapp.com">Loopy</a> lately, and want a way to track the success of various approaches.  It occurred to me that the totally freeform nature of the LinkShare &#8220;signature&#8221; field (which you can use to track traffic sources) lends itself to an even more flexible approach than that presented in the Mobile Orchard article.</p>

<p>Here&#8217;s a way to use that signature field to report the domain name of any referrer who links either to the app page, or to a download link (like, say, http://loopyapp.com/download).</p>

<p>This way, if, say, TUAW link to your app site, if someone clicks through then clicks the download link on your app site and buys, the resulting order will be reported as coming from TUAW.  If someone clicks through from your Facebook page, it&#8217;ll come up as coming from Facebook.  You can even modify the script further to report more precise details (like the path), if you like.</p>

<p>It assumes you&#8217;re using PHP, but the principle&#8217;s the same for any other language (BYO code, though ;-)).</p>

<h3>Step 1: Sign up to LinkShare</h3>

<p>First, if you haven&#8217;t already, <a href="http://click.linksynergy.com/fs-bin/click?id=/yGrgMJzFG0&amp;offerid=7097&amp;type=3&amp;subid=0">Sign up to the LinkShare program</a> &#8212; Once you&#8217;ve created a LinkShare account, join the <a href="http://cli.linksynergy.com/cli/publisher/programs/advertiser_detail.php?oid=146261&amp;mid=13508&amp;offerNid=1&amp;controls=1:1:3:0:0:1">Apple affiliate program</a> via the &#8220;Programs&#8221; tab.  After 3 days, you&#8217;ll get an email welcoming you to the program, and you&#8217;ll be good to go.</p>

<h3>Step 2: Create a product link</h3>

<p>Once you&#8217;re admitted to the program, open up the &#8220;My Advertisers&#8221; sub-tab from the LinkShare Programs tab, and open the &#8220;Link Maker Tool&#8221;. This lets you search for products, and create a link that will open up your app&#8217;s App Store page, and will be associated with your LinkShare account.</p>

<p><img style="display:block; margin-left:auto; margin-right:auto;" class="aligncenter" src="http://atastypixel.com/blog/wp-content/uploads/2011/09/Screen-Shot-2011-09-13-at-13.17.31.png" alt="Screen Shot 2011 09 13 at 13 17 31" title="Screen Shot 2011-09-13 at 13.17.31.png" border="0" width="600" height="475" /></p>

<h3>Step 3: Create a download redirection script</h3>

<p>Now we&#8217;re going to set up a script on your app site which will redirect the visitor to the URL you just created (which in turn, redirects straight to the App Store page).  It&#8217;ll add a &#8220;signature&#8221; parameter to the URL, which corresponds to the original referrer, so you can track where orders came from.</p>

<p>Create a file called &#8216;download.php&#8217; in the root of your app site, with the following content, with your LinkShare URL inserted where indicated:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// Replace the following URL with the LinkShare URL you created</span>
<span style="color: #000088;">$linkshare_url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;http://click.linksynergy.com/fs-bin/stat?id=/yGrgMJzFG0&amp;offerid=146261&amp;type=3&amp;subid=0&amp;tmpid=1826&amp;RD_PARM1=http%253A<span style="color: #009933; font-weight: bold;">%252F</span><span style="color: #009933; font-weight: bold;">%252F</span>itunes.apple.com<span style="color: #009933; font-weight: bold;">%252F</span>app<span style="color: #009933; font-weight: bold;">%252F</span>loopy<span style="color: #009933; font-weight: bold;">%252F</span>id300257824<span style="color: #009933; font-weight: bold;">%253F</span>mt%253D8<span style="color: #009933; font-weight: bold;">%2526u</span>o%253D4%2526partnerId%253D30&quot;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #990000;">session_start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$referer</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_SESSION</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'original_referer'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #000088;">$referer</span> <span style="color: #009900;">&#41;</span> <span style="color: #000088;">$referer</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;HTTP_REFERER&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$referer</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$signature</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;@https?://(?:www\.)?([^/]+?)(?:\.com)?/.*@&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;<span style="color: #006699; font-weight: bold;">$1</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$referer</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$signature</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;@^(?:www\.)?(.+?)(?:\.com)?$@&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;<span style="color: #006699; font-weight: bold;">$1</span>&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;HTTP_HOST&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #000088;">$signature</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;@[^a-zA-Z0-9]@&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;&quot;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$signature</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #990000;">header</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;Location: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$linkshare_url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;&amp;u1=&quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$signature</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>


<p>This script looks for the <em>original</em> referrer in a session variable (which we&#8217;ll set up in the next step), so that the domain of the site that links to your app site is used, not just your app site&#8217;s domain.  Then it creates a properly-formatted signature parameter (just alphanumeric), appends it to your LinkShare URL, and sends the viewer onwards.</p>

<p><em>Bonus points</em>: I prefer to get rid of the &#8216;php&#8217; extension to make the URL a bit cleaner.  Pop the following into your .htaccess file to access &#8216;download.php&#8217; as just &#8216;download&#8217;:</p>

<p><pre>
&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule . %{REQUEST_FILENAME}.php [L]
&lt;/IfModule&gt;
</pre></p>

<h3>Step 4: Remember the referrer</h3>

<p>Now, on the landing page script for your app site (or the site header), pop this in at the very start:</p>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #990000;">session_start</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #000088;">$_SESSION</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;original_referer&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span> <span style="color: #000088;">$_SESSION</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;original_referer&quot;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$_SERVER</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">&quot;HTTP_REFERER&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></div></div>


<p>This stores the original referrer URL in a session variable, to use when we actually link the viewer through to the App Store.</p>

<h3>Step 5: Test it</h3>

<p>To make sure everything&#8217;s working properly, open download.php again, and replace &#8220;header&#8221; at the bottom with &#8220;echo&#8221;, so that instead of redirecting the browser, we just print out the URL where we would be redirecting to.</p>

<p>Open your <em>appsite</em>/download URL, and make sure the URL ends with &#8220;&amp;u1=<em>appsite</em>&#8220;.  That&#8217;s for direct visitors.  Now, click through to your app site from another site, then click your &#8220;download&#8221; link.  You should now see the name of the original site you linked from as the &#8220;u1&#8243; parameter at the end of the URL.</p>

<p>Once you&#8217;re satisfied that you&#8217;re good to go, make sure you replace &#8220;echo&#8221; with &#8220;header&#8221; again.</p>

<h3>Step 6: Track</h3>

<p>Now that you&#8217;re ready to track referrals, you can give out your <em>http://yourappsite/download</em> URL as your app&#8217;s direct iTunes download link (to reviewers, in your press releases, etc).</p>

<p>You can view a report showing clicks and orders associated with each referrer on the LinkShare page &#8212; create an advanced report by clicking the &#8220;Advanced Reports&#8221; sub-tab, then select your desired date range (I use &#8220;Since Last Payment&#8221;, and under &#8220;Report Type&#8221;, select &#8220;Signature Activity&#8221;.  Hit &#8220;View Report&#8221;, and you&#8217;ll see your clicks and sales versus each referrer (&#8220;Member ID&#8221;, on the report).</p>

<p>Voila! Omnipotence achieved.</p>

<p><em>Addendum: This technique works for tracking referrers, but if you&#8217;re wanting to track the performance of ads (say, with AdMob), you&#8217;ll want to use your original LinkShare URL, with a custom &#8220;&amp;u1&#8243; signature parameter.  As ad platforms like AdMob link directly (and don&#8217;t, as far as I know, send a referer parameter), this script won&#8217;t pick up that it&#8217;s from your ad platform.</em></p>

<p><em>Addendum 2: LinkShare&#8217;s reports don&#8217;t distinguish between products, so if you&#8217;ve multiple apps, you might want to add a prefix to your signature parameter to tell &#8216;em apart. You could, say, replace that <code>header("Location: ".$linkshare_url."&amp;u1=".$signature);</code> line with something like <code>header("Location: ".$linkshare_url."&amp;u1=myapp".$signature);</code>.</em></p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2275" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/automatically-track-app-sale-referrals/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Experiments with precise timing in iOS</title>
		<link>http://atastypixel.com/blog/experiments-with-precise-timing-in-ios/</link>
		<comments>http://atastypixel.com/blog/experiments-with-precise-timing-in-ios/#comments</comments>
		<pubDate>Wed, 07 Sep 2011 16:31:18 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Audio]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Timing]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2265</guid>
		<description><![CDATA[iOS is by no means a realtime operating system, but I&#8217;m aware that NSTimer and NSObject&#8217;s performSelector:withObject:afterDelay: mechanism aren&#8217;t particularly accurate, and I was curious to see whether I could do better. Hands up, backing away Disclaimer: I am not at all an expert in realtime programming, or Mach, or iOS-device optimisation, so this is [...]]]></description>
			<content:encoded><![CDATA[<p>iOS is by no means a realtime operating system, but I&#8217;m aware that NSTimer and NSObject&#8217;s <em>performSelector:withObject:afterDelay:</em> mechanism aren&#8217;t particularly accurate, and I was curious to see whether I could do better.</p>

<h3>Hands up, backing away</h3>

<p>Disclaimer: I am not at all an expert in realtime programming, or Mach, or iOS-device optimisation, so this is pretty much a fumble in the dark.   I won&#8217;t be at all offended if anyone wishes to shoot me down and offer a more sensible solution &#8212; in fact, please do! Until then, watch as I stumble on…</p>

<p>Also note that there are often ways to eliminate the need for precise timing of this nature, by architecting code appropriately &#8212; when it comes to audio, for example, CoreAudio provides a very accurate time base in render callbacks.  For things like metronomes or audio synthesizers, it&#8217;s always better to establish a starting time, and use the difference between the current time and the starting time in order to determine state, rather than using a timer to advance the state.  Still, sometimes, you just need a timer…</p>

<h3>What the blazes?</h3>

<p>So, I&#8217;m working on an update to <a href="http://loopyapp.com">Loopy</a>, which uses a shared clock object to synchronise tracks and a variety of events (like user interface updates or timed track manipulations).  A tester noted that the mute/unmute quantisation feature that I&#8217;ve recently implemented, which will mute or unmute a loop at its starting point (rather than whenever you tap it), tends to overshoot a little, resulting in a small part of the beginning of the loop being audible.</p>

<p>Of course, there are other solutions to this particular problem (like stopping or starting playback from the audio render callback, and using Core Audio&#8217;s timestamps for exact timing), but I use timers in other places outside Core Audio&#8217;s domain, which makes Core Audio&#8217;s timing mechanism unavailable, and I wanted to see how accurate I could get the timing.</p>

<h3>Our friend, <em>mach_wait_until</em></h3>

<p>I read in several places mention of the Mach API utility <em>mach_wait_until</em> (from <em>mach/mach_time.h</em>), which is very low-level and supposedly fairly accurate.  So, based on that lead, I put together an Objective-C singleton class that launches a high-priority thread, and uses said thread to schedule events.</p>

<p>An NSArray of events are maintained, and a <em>scheduleAction:target:inTimeInterval:</em> routine creates and adds events to this array, then pokes the thread.</p>

<p>The thread grabs the next event in sequence, then uses <em>mach_wait_until</em> to sleep until the time of the next event arrives, then performs the specified action on the target.  It&#8217;s kinda a DIY NSRunLoop.</p>

<p>Here&#8217;s a comparison between this technique, and just using <em>performSelector:withObject:afterDelay:</em> (which schedules a timer on the NSRunLoop), observed while performing various scheduled events within Loopy running on my iPhone 4 with the debugger, and derived by comparing the time of event execution with the event&#8217;s scheduled time:</p>

<table>
<tr><th>Mechanism</th><th>Average discrepancy</th><th>Minimum discrepancy</th><th>Maximum discrepancy</th></tr>
<tr><td><strong>NSRunLoop</strong></td><td>16.9ms</td><td>0.25ms</td><td>153.7ms</td></tr>
<tr><td><strong>TPPreciseTimer</strong></td><td>5.5ms</td><td>0.033ms</td><td>72.0ms</td></tr>
</table>

<p>That was attempt number 1: This seems to give us about 11.4ms better accuracy on average (three times more accurate).</p>

<p>Not bad, but it turns out <em>mach_wait_until</em> isn&#8217;t really that accurate, particularly if there&#8217;s a bunch of other stuff going on in other threads.</p>

<h3>Spinning, for fun and profit</h3>

<p>For my second attempt, the thread performs a <em>mach_wait_until</em> until just before the event is due, then performs a spin lock until the time arrives, using <em>mach_absolute_time</em> to compare the current time with the target time.</p>

<p>This gave further improved results &#8212; here&#8217;s that table again, but with the new scheme added, with a few different spin lock times:</p>

<table>
<tr><th>Mechanism</th><th>Average discrepancy</th><th>Minimum discrepancy</th><th>Maximum discrepancy</th></tr>
<tr><td><strong>NSRunLoop</strong></td><td>16.9ms</td><td>0.25ms</td><td>153.7ms</td></tr>
<tr><td><strong>TPPreciseTimer (original)</strong></td><td>5.5ms</td><td>0.033ms</td><td>72.0ms</td></tr>
<tr><td><strong>TPPreciseTimer (10ms spinlock)</strong></td><td>6.0ms</td><td>0.002ms</td><td>76.5ms</td></tr>
<tr><td><strong>TPPreciseTimer (100ms spinlock)</strong></td><td>3.7ms</td><td>0.002ms</td><td>44.8ms</td></tr>
<tr><td><strong>TPPreciseTimer (200ms spinlock)</strong></td><td>2.91ms</td><td>0.002ms</td><td>74.1ms</td></tr>
</table>

<p>It appears that the more stuff there is going on in other threads, the more likely the <em>mach_absolute_time</em> call is to overshoot.  So, the more time spent in the spin lock, the more leeway <em>mach_absolute_time</em> has to wait too long.  Of course, that&#8217;s at the cost of making the CPU twiddle its thumbs for the duration.</p>

<h3>Better than a punch in the knee</h3>

<p>The results weren&#8217;t quite as fantastic as I&#8217;d hoped &#8212; still within the same order of magnitude, that&#8217;s for sure &#8212; but the average case for the 200ms spinlock approach is 14ms, or 5.8 times, more accurate than the traditional approach, and the minimum case is dramatically better.</p>

<p>You know, I think if I was aware of the results in advance, I might not bother, but I&#8217;ll stick with my hard-won 14ms now that I&#8217;m here (that&#8217;s 617 audio samples, I&#8217;ll have you know).</p>

<p>If anyone&#8217;s curious about the implementation (or wants to take a stab at doing better), here it is, along with a wildly simplistic commandline test app: <a href="http://atastypixel.com/blog/wp-content/uploads/2011/09/TPPreciseTimer.zip" title="TPPreciseTimer.zip" alt="TPPreciseTimer">TPPreciseTimer.zip</a></p>

<p>Now to get back to some real work.</p>

<h3>Addendum: GCD follow-up</h3>

<p>Chris in the comments below suggested trying a GCD-based approach, using <em>dispatch_after</em>.  Curious, I rigged it up, and these are the stats, collected the same way as above, added to the prior table:</p>

<table>
<tr><th>Mechanism</th><th>Average discrepancy</th><th>Minimum discrepancy</th><th>Maximum discrepancy</th></tr>
<tr><td><strong>NSRunLoop</strong></td><td>16.9ms</td><td>0.25ms</td><td>153.7ms</td></tr>
<tr><td><strong>TPPreciseTimer (original)</strong></td><td>5.5ms</td><td>0.033ms</td><td>72.0ms</td></tr>
<tr><td><strong>TPPreciseTimer (10ms spinlock)</strong></td><td>6.0ms</td><td>0.002ms</td><td>76.5ms</td></tr>
<tr><td><strong>TPPreciseTimer (100ms spinlock)</strong></td><td>3.7ms</td><td>0.002ms</td><td>44.8ms</td></tr>
<tr><td><strong>TPPreciseTimer (200ms spinlock)</strong></td><td>2.91ms</td><td>0.002ms</td><td>74.1ms</td></tr>
<tr><td><strong>dispatch_after (main queue)</strong></td><td>14.8ms</td><td>0.16ms</td><td>161.2ms</td></tr>
<tr><td><strong>dispatch_after (dedicated queue)</strong></td><td>19.2ms</td><td>0.1ms</td><td>174.9ms</td></tr>
<tr><td><strong>dispatch_after (dedicated queue + 100ms spinlock)</strong></td><td>22.4ms</td><td>0.002ms</td><td>306.8ms</td></tr>
</table>

<p>So, they appear pretty much the same as the NSRunLoop stats.</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2265" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/experiments-with-precise-timing-in-ios/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Sparrow users beware: Bug sends prior draft instead of latest email version</title>
		<link>http://atastypixel.com/blog/sparrow-users-beware-bug-sends-prior-draft-instead-of-latest-email-version/</link>
		<comments>http://atastypixel.com/blog/sparrow-users-beware-bug-sends-prior-draft-instead-of-latest-email-version/#comments</comments>
		<pubDate>Thu, 18 Aug 2011 19:41:50 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Email]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Sparrow]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2243</guid>
		<description><![CDATA[Update: The Sparrow guys tell me they&#8217;ve found and nailed the bug, and will release the fix in 1.4 in late September. I&#8217;ve just discovered a critical issue with Sparrow that I thought others should be warned of. It just bit me, big-time, when in the middle of an important negotiation with a third party, [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update</strong>: <em>The Sparrow guys tell me they&#8217;ve found and nailed the bug, and will release the fix in 1.4 in late September.</em></p>

<p>I&#8217;ve just discovered a critical issue with Sparrow that I thought others should be warned of.  It just bit me, big-time, when in the middle of an important negotiation with a third party, an earlier unpolished draft was sent out instead of the final email, when I experienced a momentary Internet connection dropout.</p>

<p>Sparrow has an issue where hitting &#8220;Send&#8221;, in unreliable network conditions, on a draft message that has been modified, results in a prior copy of the message being sent, rather than the latest version.</p>

<p>To replicate this issue reliably:</p>

<ol>
<li>Create a new message (Cmd-N)</li>
<li>Specify a recipient (oneself), subject, and some body content (say, the letter &#8220;A&#8221;)</li>
<li>Hit &#8220;Save&#8221;, to save the draft</li>
<li>Change &#8220;A&#8221; to &#8220;B&#8221;, then disconnect the network connection (in my case, turning off the radio on my external WiFi adapter), then hit &#8220;Send&#8221;.  Sparrow will report a failed connection, and will keep the outgoing message with state &#8220;Pending&#8221;</li>
<li>Restore network connection.  Upon detecting the restored connection, Sparrow will proceed to send the message</li>
<li>Check email. Received test email will have &#8220;A&#8221; in the email body.</li>
</ol>

<p>Scary stuff.  I hope they&#8217;ll fix this soon, but it&#8217;s going to make the app difficult to trust in future!</p>

<p><strong>Update</strong>: I should mention, a probable workaround for this is to never, ever hit &#8220;Send&#8221; until you&#8217;ve saved the draft, and verified that the save operation has completed (perhaps even restart the app first).</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2243" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/sparrow-users-beware-bug-sends-prior-draft-instead-of-latest-email-version/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Seamlessly manage portrait and landscape view controller layouts</title>
		<link>http://atastypixel.com/blog/seamlessly-manage-portrait-and-landscape-view-controller-layouts/</link>
		<comments>http://atastypixel.com/blog/seamlessly-manage-portrait-and-landscape-view-controller-layouts/#comments</comments>
		<pubDate>Sun, 14 Aug 2011 17:43:34 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Utility]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/?p=2239</guid>
		<description><![CDATA[A headache-inducing scenario: I&#8217;m working on a view controller, and I realise that in order to support landscape and portrait modes, I&#8217;m going to need to provide two different layouts. So, I create two different views within the nib, one portrait, one landscape, each with the same view hierarchy, but with a different layout. When [...]]]></description>
			<content:encoded><![CDATA[<p>A headache-inducing scenario: I&#8217;m working on a view controller, and I realise that in order to support landscape and portrait modes, I&#8217;m going to need to provide two different layouts.</p>

<p>So, I create two different views within the nib, one portrait, one landscape, each with the same view hierarchy, but with a different layout.</p>

<p>When the orientation changes, I set <code>self.view</code> to the appropriate view.  I initialise both views on load, and keep both of them synced to properly reflect the app&#8217;s state &#8212; basically, <strong>I&#8217;m double-handling everything</strong>, which bloats my code and increases the chance I&#8217;ll make a mistake.</p>

<p>So, here&#8217;s an easier way: Rather than maintaining two separate view hierarchies and switching between them when the orientation changes, why not just change the layout of one single view hierarchy?  The only changes between the portrait and landscape views are layout changes, so if we can extract just the layout information from each view, then we don&#8217;t have to worry about maintaining both view hierarchies.</p>

<p>Basically, we&#8217;re talking about using each view version as a <strong>layout template</strong> only.</p>

<p>That&#8217;s what <a href="https://github.com/michaeltyson/TPMultiLayoutViewController">TPMultiLayoutViewController</a> class does.  It&#8217;s a drop-in UIViewController subclass that automatically manages switching between different view layouts for portrait and landscape orientations, without the need to maintain view state across two different view hierarchies.</p>

<p>It works by defining <code>portraitView</code> and <code>landscapeView</code> outlets which it traverses upon loading the nib.  It matches each subview element to its counterpart in the other layout (based on tag, target/action, title, etc.), and stores just the layout attributes of each element.</p>

<p>Then, when the orientation changes, the view hierarchy is traversed and these layouts are applied to each subview.</p>

<p>To use it,</p>

<ol>
<li>Set the superclass for your view controller to <code>TPMultiLayoutViewController</code>.</li>
<li>In Interface Builder, create two different views: one for portrait orientation, and one for landscape orientation.</li>
<li>Attach your portrait orientation root view to the &#8220;portraitView&#8221; outlet, and the landscape orientation root view to the &#8220;landscapeView&#8221; outlet.</li>
<li>Attach one of the views (whichever you prefer) to the &#8220;view&#8221; outlet, and connect any actions and outlets from that view.</li>
</ol>

<p>Grab it from the <a href="https://github.com/michaeltyson/TPMultiLayoutViewController">TPMultiLayoutViewController GitHub repository</a>, and let me know what you think.</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2239" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/seamlessly-manage-portrait-and-landscape-view-controller-layouts/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Fixing Xcode 4&#8242;s symbolicate utility to get comprehensible crash logs</title>
		<link>http://atastypixel.com/blog/fixing-xcode-4s-symbolicate-utility-to-get-comprehensible-crash-logs/</link>
		<comments>http://atastypixel.com/blog/fixing-xcode-4s-symbolicate-utility-to-get-comprehensible-crash-logs/#comments</comments>
		<pubDate>Sun, 03 Jul 2011 19:30:58 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Scripts]]></category>
		<category><![CDATA[XCode]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/fixing-xcode-4s-symbolicate-utility-to-get-comprehensible-crash-logs/</guid>
		<description><![CDATA[&#8216;symbolicatecrash&#8217; is the Developer Tools utility which replaces all those meaningless addresses from crash logs with actual symbol names and source code references. It lives at some obscure folder within /Developer &#8211; use find to dig it up and symlink it into /usr/local/bin if you wanna use it conveniently from the command line. Anyway, after [...]]]></description>
			<content:encoded><![CDATA[<p>&#8216;symbolicatecrash&#8217; is the Developer Tools utility which replaces all those meaningless addresses from crash logs with actual symbol names and source code references.  It lives at some obscure folder within <code>/Developer</code> &#8211; use <code>find</code> to dig it up and symlink it into <code>/usr/local/bin</code> if you wanna use it conveniently from the command line.</p>

<p>Anyway, after plenty of frustration, I noticed some chatter about the damn thing being busted in Xcode 4.  Figures!</p>

<p>There&#8217;s an <a href="https://github.com/fourdman/symbolicatecrash-fix">alternate third party version</a> on GitHub, but this didn&#8217;t really help me &#8211; I still got inscrutable errors, so I took a look at the original.</p>

<p>The version that comes with Xcode 4 appears to have some problems distinguishing, say, an iPhone Simulator build of the app from a native build sitting in the Archives folder.  I&#8217;d just see an error about otool and some binary living in the iPhone Simulator folder.</p>

<p>Digging into the errant symbolicatecrash source, I noticed that the code that finds the executable path tests each candidate using otool, but doesn&#8217;t seem to be able to comprehend the output from otool caused by running it on the wrong architecture.</p>

<p>So, replacing the rather unhelpful &#8216;die&#8217; statement on line 323:</p>

<p><code>die "Can't understand the output from otool ($TEST_uuid -&gt; '$otool -arch $arch -l $path')";</code></p>

<p>With a &#8220;No, it ain&#8217;t this executable&#8221; response:</p>

<p><code>return 0;</code></p>

<p>&#8230;solves the problem immediately.  Now I can drag crash logs straight into the Organizer in Xcode, and it&#8217;ll symbolicate correctly.</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2199" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/fixing-xcode-4s-symbolicate-utility-to-get-comprehensible-crash-logs/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Post Grabber sniffs out POST data, generates curl scripts</title>
		<link>http://atastypixel.com/blog/post-grabber-sniffs-out-post-data-generates-curl-scripts/</link>
		<comments>http://atastypixel.com/blog/post-grabber-sniffs-out-post-data-generates-curl-scripts/#comments</comments>
		<pubDate>Thu, 21 Apr 2011 08:59:04 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Utility]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/post-grabber-sniffs-out-post-data-generates-curl-scripts/</guid>
		<description><![CDATA[Every now and then I find myself needing to automate some web requests, either to download using something a little more robust than a web browser, scrape some web content, or to maintain a session. That automation can be a bit of a pain if there&#8217;s a form submission involved, because it means opening up [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://atastypixel.com/blog/wp-content/uploads/2011/04/michaeltyson_PostGrabber_raw_master_screenshot.png" width="300" height="294" alt="Post Grabber screenshot" class="alignright" />Every now and then I find myself needing to automate some web requests, either to download using something a little more robust than a web browser, scrape some web content, or to maintain a session.  That automation can be a bit of a pain if there&#8217;s a form submission involved, because it means opening up the page source, finding the form and any connected javascript code, and figuring out what fields are submitted.</p>

<p>A little utility I just put together does that for you: <a href="https://github.com/michaeltyson/PostGrabber">Post Grabber</a> detects POST data and generates an equivalent &#8220;curl&#8221; command that can be used in shell or Automator scripts.</p>

<p>Post Grabber works with its own internal browser, so it can intercept POST submissions directly. That means it works with HTTPS, unlike the traditional web sniffer approach.</p>

<p><a href="https://github.com/downloads/michaeltyson/PostGrabber/Post%20Grabber%201.2.zip">Download the app</a>, or see the <a href="https://github.com/michaeltyson/PostGrabber">source on GitHub</a>.</p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2189" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/post-grabber-sniffs-out-post-data-generates-curl-scripts/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>A drop-in universal solution for moving text fields out of the way of the keyboard</title>
		<link>http://atastypixel.com/blog/a-drop-in-universal-solution-for-moving-text-fields-out-of-the-way-of-the-keyboard/</link>
		<comments>http://atastypixel.com/blog/a-drop-in-universal-solution-for-moving-text-fields-out-of-the-way-of-the-keyboard/#comments</comments>
		<pubDate>Tue, 12 Apr 2011 11:26:21 +0000</pubDate>
		<dc:creator>Michael Tyson</dc:creator>
				<category><![CDATA[Geekspeak]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://atastypixel.com/blog/a-drop-in-universal-solution-for-moving-text-fields-out-of-the-way-of-the-keyboard/</guid>
		<description><![CDATA[There are a hundred and one proposed solutions out there for how to move UITextField and UITextView out of the way of the keyboard during editing &#8212; usually, it comes down to observing UIKeyboardWillShowNotification and UIKeyboardWillHideNotification, or implementing UITextFieldDelegate delegate methods, and adjusting the frame of the superview, or using UITableView&#8216;s scrollToRowAtIndexPath:atScrollPosition:animated:, but all the [...]]]></description>
			<content:encoded><![CDATA[<p>There are a hundred and one proposed solutions out there for how to move <code>UITextField</code> and <code>UITextView</code> out of the way of the keyboard during editing &#8212; usually, it comes down to observing <code>UIKeyboardWillShowNotification</code> and <code>UIKeyboardWillHideNotification</code>, or implementing <code>UITextFieldDelegate</code> delegate methods, and adjusting the frame of the superview, or using <code>UITableView</code>&#8216;s <code>scrollToRowAtIndexPath:atScrollPosition:animated:</code>, but all the proposed solutions I&#8217;ve found tend to be quite DIY, and have to be implemented for each view controller that needs it.</p>

<p>I thought I&#8217;d put together a relatively universal, drop-in solution: <code>UIScrollView</code> and <code>UITableView</code> subclasses that handle everything.</p>

<p>When the keyboard is about to appear, the subclass will find the subview that&#8217;s about to be edited, and adjust its frame and content offset to make sure that view is visible, with an animation to match the keyboard pop-up. When the keyboard disappears, it restores its prior size.</p>

<p>It should work with basically any setup, either a UITableView-based interface, or one consisting of views placed manually.</p>

<p></p>

<p><span id="more-2185"></span><img src="http://atastypixel.com/blog/wp-content/uploads/2011/04/201104121152.jpg" width="270" height="234" alt="201104121152.jpg" class="alignright" />For non-UITableViewControllers, use it as-is by dropping the <code>TPKeyboardAvoidingScrollView</code> source files into your project, popping a <code>UIScrollView</code> into your view controller&#8217;s xib, setting the class to <code>TPKeyboardAvoidingScrollView</code>, and putting all your controls within that scroll view.</p>

<p>To use it with UITableViewController, pop the <code>TPKeyboardAvoidingTableView</code> source files in, and just make your UITableView a <code>TPKeyboardAvoidingTableView</code> in the xib &#8212; everything should be taken care of.</p>

<p>You can grab the source files, which includes a sample project, over on the <a href="https://github.com/michaeltyson/TPKeyboardAvoiding">GitHub project page</a></p>
 <img src="http://atastypixel.com/blog/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=2185" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://atastypixel.com/blog/a-drop-in-universal-solution-for-moving-text-fields-out-of-the-way-of-the-keyboard/feed/</wfw:commentRss>
		<slash:comments>64</slash:comments>
		</item>
	</channel>
</rss>

