<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xml:lang="en" xml:base="http://jeffreysambells.com/wp-atom.php">
	<title type="text">Jeffrey Sambells</title>
	<subtitle type="text">Geek out AFK</subtitle>

	<updated>2012-05-14T16:04:01Z</updated>

	<link rel="alternate" type="text/html" href="http://jeffreysambells.com" />
	<id>http://jeffreysambells.com/feed/atom/</id>
	

	<generator uri="http://wordpress.org/" version="3.3.2">WordPress</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/iamamused" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="iamamused" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; Backup]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/05/14/backup/" />
		<id>http://jeffreysambells.com/?p=1653</id>
		<updated>2012-05-14T16:04:01Z</updated>
		<published>2012-05-14T16:02:54Z</published>
		<category scheme="http://jeffreysambells.com" term="Miscellaneous" />		<summary type="html"><![CDATA[Backups are important. I&#8217;ve had several drives spontaneously stop working over the years and had I not had backups my children would not have cherished memories of their childhood. I&#8217;m so paranoid that I have backups of the backups of the backups. And if you think it won&#8217;t happen to you, here&#8217;s a little story [...]<p><a href="http://jeffreysambells.com/posts/2012/05/14/backup/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/05/14/backup/"><![CDATA[<p>Backups are important. I&#8217;ve had several drives spontaneously stop working over the years and had I not had backups my children would not have cherished memories of their childhood. I&#8217;m so paranoid that I have backups of the backups of the backups. And if you think it won&#8217;t happen to you, here&#8217;s a little story about how how Pixar almost deleted Toy Story 2.</p>

<iframe width="560" height="315" src="http://www.youtube.com/embed/EL_g0tyaIeE" frameborder="0" allowfullscreen></iframe>

<p>So go backup your stuff. Right Now. Seriously.</p>

<p>(via <a href="http://kottke.org/12/05/how-pixar-almost-deleted-toy-story-2">kottke.org</a>)</p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/05/14/backup/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/05/14/backup/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; Focus on the Primary Task]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/05/11/focus-on-the-primary-task/" />
		<id>http://jeffreysambells.com/?p=1641</id>
		<updated>2012-05-11T04:05:44Z</updated>
		<published>2012-05-11T04:05:44Z</published>
		<category scheme="http://jeffreysambells.com" term="How-To" /><category scheme="http://jeffreysambells.com" term="Mobile" />		<summary type="html"><![CDATA[This post, Focus on the Primary Task, is the first in a series of posts that was inspired by the Table of Contents in Apple&#8217;s iOS Human Interface Guidelines. I&#8217;m intending to write a post about each heading, expanding on what Apple discusses and how it relates to the general process of mobile application development. [...]<p><a href="http://jeffreysambells.com/posts/2012/05/11/focus-on-the-primary-task/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/05/11/focus-on-the-primary-task/"><![CDATA[<p><em>This post, Focus on the Primary Task, is the first in a series of posts that was inspired by the Table of Contents in <a href="http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html#//apple_ref/doc/uid/TP40006556-CH20-SW1">Apple&#8217;s iOS Human Interface Guidelines</a>. I&#8217;m intending to write a post about each heading, expanding on what Apple discusses and how it relates to the general process of mobile application development.</em></p>

<blockquote>
  <p>it comes from saying no to 1,000 things to make sure we don&#8217;t get on the wrong track or try to do too much &#8230; it&#8217;s only by saying no that you can concentrate on the things that are really important.</p>
</blockquote>

<p><cite>Steve jobs, &#8220;The Seed of Apple&#8217;s Innovation&#8221; in BusinessWeek (12 October 2004)</cite></p>

<p>There&#8217;s a mantra in mobile apps that says you will succeed if you do one thing and do it extremely well. The best mobile apps, those that are most popular, most satisfying and most enjoyable all pick one thing, a method, a behaviour, a feature, an idea, and execute it perfectly. They allow you to achieve your goal so well you&#8217;re dumfounded that it could be that easy, or that no-one had thought of it before. Being focused, doesn&#8217;t mean the app has to be simple like the <a href="http://agiletortoise.com/drafts">Drafts</a> note taking app or the <a href="http://www.realmacsoftware.com/clear/">Clear</a> task manager. An app such as <a href="http://www.instapaper.com">Instapaper</a>, <a href="http://campl.us">Camera+</a>, <a href="http://itunes.apple.com/ca/app/path/id403639508?mt=8">Path</a> or even <a href="http://www.angrybirds.com">Angry Birds</a> can have lots of features, screens and doo-dads but each addition is focused to support and contribute to the app&#8217;s overall focus.</p>

<p>To help guide and focus your app you need to clearly define its purpose and audience. Apple&#8217;s iOS Human Interface Guidelines call this the <a href="http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/MobileHIG/AppDesign/AppDesign.html#//apple_ref/doc/uid/TP40006556-CH19-SW2"><em>Application Definition Statement</em></a>, &#8220;a concise, concrete declaration of an app’s main purpose and its intended audience.&#8221;</p>

<p>The primary goal of the application definition statement it to enable you to say NO whenever possible. Does this screen really support the focus of the app? NO. Is this feature actually useful to the majority of the audience? NO.</p>

<p>To create your statement just follow these few steps:</p>

<ol>
<li>Go crazy and brainstorm a list of every conceivable feature you think could be in your app. Make each point brief but make this list long. Write down anything and everything you can possibly think of. The more the better.</li>
<li>Decide who your primary users will be. Skip the obvious mobile user cliches such as &#8220;they&#8217;ll be mobile&#8221; or &#8220;they want it to be simple&#8221;. What you&#8217;re trying to define here is what distinguishes your users from everyone else. What things are important for users when they use your app? Write down the top three to five things.</li>
<li>Now start crossing features off your list that don&#8217;t jive with your audience. Some of the features will be easy to cross off but you&#8217;ll find many that seem to be useful so you&#8217;ll have to make some tough decisions. Regardless, keep saying no, and then say no again. Keep going until you&#8217;re left with only a few items.</li>
</ol>

<p>What&#8217;s left are your core focus, your most important ideas. These ideas will sell the app and make it awesome. Every decision, behaviour, element, control, screen, interaction, and word on the screen will focus on doing these few items and doing them exceptionally well. Do that and your app will rock.</p>

<p>When your app evolves or the audience changes, you can always return to your application definition statement and refine the focus of your app. If it changes too frequently it&#8217;s a sign you&#8217;re not focused enough. Also, if&#8211;and when&#8211;it does change, don&#8217;t be afraid to remove an existing feature that no longer makes sense.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/05/11/focus-on-the-primary-task/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/05/11/focus-on-the-primary-task/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; Mobile User Experience Guidelines]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/04/27/mobile-user-experience-guidelines/" />
		<id>http://jeffreysambells.com/?p=1636</id>
		<updated>2012-04-27T14:27:29Z</updated>
		<published>2012-04-27T14:27:29Z</published>
		<category scheme="http://jeffreysambells.com" term="Miscellaneous" />		<summary type="html"><![CDATA[Can&#8217;t think of a better list than the table of contents in Apple&#8217;s iOS Human Interface Guidelines: Focus on the Primary Task Elevate the Content that People Care About Think Top Down Give People a Logical Path to Follow Make Usage Easy and Obvious Use User-Centric Terminology Minimize the Effort Required for User Input Downplay [...]<p><a href="http://jeffreysambells.com/posts/2012/04/27/mobile-user-experience-guidelines/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/04/27/mobile-user-experience-guidelines/"><![CDATA[<p>Can&#8217;t think of a better list than the table of contents in <a href="http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/MobileHIG/UEBestPractices/UEBestPractices.html#//apple_ref/doc/uid/TP40006556-CH20-SW1">Apple&#8217;s iOS Human Interface Guidelines</a>:</p>

<ul>
<li>Focus on the Primary Task</li>
<li>Elevate the Content that People Care About</li>
<li>Think Top Down</li>
<li>Give People a Logical Path to Follow</li>
<li>Make Usage Easy and Obvious</li>
<li>Use User-Centric Terminology</li>
<li>Minimize the Effort Required for User Input</li>
<li>Downplay File-Handling Operations</li>
<li>Enable Collaboration and Connectedness</li>
<li>De-emphasize Settings</li>
<li>Brand Appropriately</li>
<li>Make Search Quick and Rewarding</li>
<li>Entice and Inform with a Well-Written Description</li>
<li>Be Succinct</li>
<li>Use UI Elements Consistently</li>
<li>Consider Adding Physicality and Realism</li>
<li>Delight People with Stunning Graphics</li>
<li>Handle Orientation Changes</li>
<li>Make Targets Fingertip-Size</li>
<li>Use Subtle Animation to Communicate</li>
<li>Support Gestures Appropriately</li>
<li>Ask People to Save Only When Necessary</li>
<li>Make Modal Tasks Occasional and Simple</li>
<li>Start Instantly</li>
<li>Always Be Prepared to Stop</li>
<li>Don’t Quit Programmatically</li>
<li>If Necessary, Display a License Agreement or Disclaimer</li>
<li>Enhance Interactivity (Don’t Just Add Features)</li>
<li>Reduce Full-Screen Transitions</li>
<li>Restrain Your Information Hierarchy</li>
<li>Consider Using Popovers for Some Modal Tasks</li>
<li>Migrate Toolbar Content to the Top</li>
</ul>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/04/27/mobile-user-experience-guidelines/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/04/27/mobile-user-experience-guidelines/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; Custom Fonts in iOS]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/04/24/custom-fonts-in-ios/" />
		<id>http://jeffreysambells.com/?p=1629</id>
		<updated>2012-04-24T14:08:29Z</updated>
		<published>2012-04-24T14:07:44Z</published>
		<category scheme="http://jeffreysambells.com" term="Miscellaneous" />		<summary type="html"><![CDATA[Quick How-To for loading custom fonts in iOS apps: Add the font file to your project the same way you would with other files. Some great open source fonts I&#8217;m using in an upcoming project are available from The League of Moveable Type. Edit your info plist to reference the newly added font file (here [...]<p><a href="http://jeffreysambells.com/posts/2012/04/24/custom-fonts-in-ios/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/04/24/custom-fonts-in-ios/"><![CDATA[<p>Quick How-To for loading custom fonts in iOS apps:</p>

<ol>
<li>Add the font file to your project the same way you would with other files. Some great open source fonts I&#8217;m using in an upcoming project are available from <a href="http://theleagueofmoveabletype.com">The League of Moveable Type</a>.</li>
<li><p>Edit your info plist to reference the newly added font file (here for example MyFont.otf):</p>

<pre><code>&lt;key&gt;UIAppFonts&lt;/key&gt;
&lt;array&gt;
    &lt;string&gt;MyFont.otf&lt;/string&gt;
&lt;/array&gt;
</code></pre></li>
<li><p>Set the font for the desired view in code, for example:</p>

<pre><code>[self.someLabel setFont:[UIFont fontWithName:@"My Font" size:24.0f]];
</code></pre></li>
</ol>

<p><strong>NOTE:</strong> The tricky part is the font name. The plist needs to reference the font file name such as <code>MyFont.otf</code> but <code>UIFont fontWithName:</code> uses the system&#8217;s font name, not the file name. Sometimes the system name is very different from the truncated file name such as <code>OFLGoudyStM-Italic.otf</code> and <code>OFL Sorts Mill Goudy</code>.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/04/24/custom-fonts-in-ios/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/04/24/custom-fonts-in-ios/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; More on Bloat]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/03/19/more-on-bloat/" />
		<id>http://jeffreysambells.com/?p=1615</id>
		<updated>2012-03-19T16:26:44Z</updated>
		<published>2012-03-19T14:27:06Z</published>
		<category scheme="http://jeffreysambells.com" term="Apple" /><category scheme="http://jeffreysambells.com" term="How-To" /><category scheme="http://jeffreysambells.com" term="iOS" /><category scheme="http://jeffreysambells.com" term="iPad" /><category scheme="http://jeffreysambells.com" term="iPhone" /><category scheme="http://jeffreysambells.com" term="Mobile" /><category scheme="http://jeffreysambells.com" term="Resolutions" /><category scheme="http://jeffreysambells.com" term="User Interface" /><category scheme="http://jeffreysambells.com" term="XCode" />		<summary type="html"><![CDATA[The other day I talked about the retina display bloat and using vectors to vastly decrease the distribution size of your iOS apps. The drawback however was that it only work for image that can be vectorized. So what about the rest of your images like photos or the default screens? Well, it turns out [...]<p><a href="http://jeffreysambells.com/posts/2012/03/19/more-on-bloat/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/03/19/more-on-bloat/"><![CDATA[<p>The other day I talked about the retina display bloat and <a href="http://jeffreysambells.com/posts/2012/03/02/beating-the-20mb-size-limit-ipad-retina-displays/">using vectors to vastly decrease the distribution size of your iOS apps</a>. The drawback however was that it only work for image that can be vectorized. So what about the rest of your images like photos or the default screens?</p>

<p>Well, it turns out that the built-in Xcode PNG compression tool kinda lacks in the compression department. There&#8217;s a <a href="http://imageoptim.com/tweetbot.html">great case study</a> about the Tweetbot app over on the ImageOptimum site:</p>

<blockquote>
  <p>Disabling Xcode conversion and simply using ImageOptim instead was enough to reduce the application size by almost 30% (33.4MB down to 23.8MB) and halve initial display time.</p>
  
  <p>Manually optimizing images with ImageAlpha reduced entire application size by more than a half (33.4MB down to 16.3MB). Images alone were 65% smaller and were displayed 2.5 times quicker than Xcode-optimized ones.</p>
</blockquote>

<p>Now that&#8217;s awesome. If a few clicks can save you megabytes why not?</p>

<p>It turns out that Xcode creates a CgBI PNG varient optimized for loading speed using 32-bit BGRA. Jeff LaMarche has <a href="http://iphonedevelopment.blogspot.ca/2008/10/iphone-optimized-pngs.html">a great technical explanation</a> of what&#8217;s going on, explaining that Xcode basically optimizes for loading speed by swapping bytes in the image and &#8220;corrupting&#8221; the PNG format.</p>

<blockquote>
  <p>During the build, Xcode basically screws up your PNG image, turning it into something that&#8217;s technically no longer a PNG image. Xcode doesn&#8217;t change your original file, but when it copies it to the Resources folder of your application bundle, what it does is it byte-swaps the red and blue octets and also &#8220;premultiplies the alpha&#8221; &#8230; The PNG specification does not support either of these changes</p>
</blockquote>

<p>The other downside is that sometimes this manipulation results in a <em>larger</em> file size than you would have with a normally optimized PNG.</p>

<p>To disable Xcode&#8217;s built in image compression, go to your target&#8217;s build settings, filter for &#8220;Compress PNG Files&#8221; and select NO.</p>

<p>However, be cautious if you choose to disable Xcode&#8217;s built-in PNG optimization and do the optimization yourself with a tool like <a href="http://imageoptim.com/">ImageOptimum</a>. Disabling Xcode&#8217;s optimization will mean your iDevice will do the equivalent optimization on-the-fly at run-time, adding additional processing and memory overhead. You should to take this into consideration and optimize your code to share and reuse image resources where possible.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/03/19/more-on-bloat/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/03/19/more-on-bloat/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; Beating the retina display bloat]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/03/02/beating-the-20mb-size-limit-ipad-retina-displays/" />
		<id>http://jeffreysambells.com/?p=1583</id>
		<updated>2012-03-19T13:43:50Z</updated>
		<published>2012-03-02T15:30:04Z</published>
		<category scheme="http://jeffreysambells.com" term="iOS" /><category scheme="http://jeffreysambells.com" term="iPad" /><category scheme="http://jeffreysambells.com" term="iPhone" /><category scheme="http://jeffreysambells.com" term="ios" /><category scheme="http://jeffreysambells.com" term="retina" />		<summary type="html"><![CDATA[TL:DR The iPad retina display is going to cause bloat in app sizes beyond the 20MB 50MB 3G download limit. Instead use vector images to render assets on-the-fly as shown in this GIST and this example Xcode project. With the imminent announcement of the iPad 3 and the much rumoured Retina display, developers are beginning [...]<p><a href="http://jeffreysambells.com/posts/2012/03/02/beating-the-20mb-size-limit-ipad-retina-displays/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/03/02/beating-the-20mb-size-limit-ipad-retina-displays/"><![CDATA[<p><strong>TL:DR The iPad retina display is going to cause bloat in app sizes beyond the <strike>20MB</strike> 50MB 3G download limit. Instead use vector images to render assets on-the-fly as shown in <a href="https://gist.github.com/1955318">this GIST</a> and <a href="https://github.com/iamamused/AssetsFromPDF">this example Xcode project</a>.</strong></p>

<p>With the imminent announcement of the iPad 3 and the much rumoured Retina display, developers are beginning to scramble to include new high res images in their iPad apps. But, as <a href="http://thenextweb.com/apple/2012/03/02/ipad-3s-retina-display-mans-trouble-for-many-apps-due-to-apples-20mb-3g-download-limit/">Matthew Panzarino at The Next Web</a> and <a href="http://www.macstories.net/stories/retina-universal/">Federico Viticci at Mac Stories</a> point out, this introduces a growing problem where many universal apps will suddenly balloon in size and tip over the 20MB 3G download limit.</p>

<p>Consider the default splash screen. For a single orientation it requires 4 images in a universal app:</p>

<ol>
<li>320&#215;420 for iPhone non retina</li>
<li>640&#215;480 for iPhone retina</li>
<li>768&#215;1024 for iPad</li>
<li>1536&#215;2048 for iPad retina (assuming)</li>
</ol>

<p>Using a random photo, the file size for these was around:</p>

<ol>
<li>217 KB</li>
<li>789 KB</li>
<li>900 KB</li>
<li>2400 KB</li>
</ol>

<p>I&#8217;m sure there&#8217;s some optimization that could be done there but still, that&#8217;s a total of around 4.2 MB, just for the splash screen images. Double that for landscape and you&#8217;re already at almost half your 20MB and you haven&#8217;t included any code yet.</p>

<p>The articles linked above point out two possible solutions.</p>

<ol>
<li><p>Get carries to allow an increase in the file size limit. I agree that 20MB is kind of small, even now with many podcasts over the limit, so this makes sense but at the same time it doesn&#8217;t really solve the problem. Bloated apps with lots of unused resources will quickly fill up or iDevices and will only increase the traffic on the already strained 3G networks.</p></li>
<li><p>Have Apple implement a method to identify which device is downloading the app and only include the appropriate resources. I like this idea but it would require a rethinking of the application packaging process and probably wouldn&#8217;t be backwards compatible with existing iOS versions.</p></li>
</ol>

<p>The above two solutions have their pros and cons but thinking about the actual problem there&#8217;s a third&#8211;and in my opinion much better&#8211;option that you can do today: don&#8217;t include the PNG images at all. Instead, use vector images in-app to generate the necessary assets on-the-fly. It won&#8217;t work for photos or large texture images but I&#8217;ve already used this technique in several apps and it works extremely well in most cases. It also has several advantages:</p>

<ol>
<li>The overall application size is considerably reduced. There&#8217;s no big retina image to download.</li>
<li>Each device only contains the necessary image assets for itself. No retina screen? no waste of precious storage space for retina images.</li>
<li>Less human time required. You only need to include the original vector image (as a PDF), no need to create four copies of every image for various resolutions and file names.</li>
<li><em>Super huge bonus:</em> your app <strong>won&#8217;t need any updates</strong> to have retina graphics on a new fancy iPad! It&#8217;ll &#8220;just work&#8221; day one.</li>
</ol>

<p>The only disadvantages are when the first time the image is displayed. Since it doesn&#8217;t exist it will take a moment to load while the the image assets are generated and stored. Depending on the number of different images you have on the screen this could add a bit of loading time, but only the first time. With some creative background threading and appropriate care the impact can be easily minimized. As well, it won&#8217;t work for the icon and default image since those can&#8217;t be modified by the app so you&#8217;re still stuck with the images there.</p>

<h2>Generating image assets on-the-fly</h2>

<p>So how do we go about doing this? All we need is a vector image saved as a PDF and a bit of rendering code. Then, when you first need the image you just render the pdf to the appropriate PNG resource for the device.</p>

<p><a href="https://gist.github.com/1955318">Here&#8217;s an example GIST using a PDF to render an image</a> (embedded below) or <a href="https://github.com/iamamused/AssetsFromPDF">an example as a complete Xcode project</a>.</p>

<p>The basic idea is you have a PDF in your project resources and you load it in the background like this:</p>

<pre><code>UIImage *myImage = [LoadImageExample LoadImageFromFile:"example" forRect:CGRectMake(0,0,100,100));

UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.frame];
[imageView setContentMode:UIViewContentModeCenter];
[self.view addSubview:imageView];

[LoadImage LoadFromPDF:@"apple_logo" size:CGSizeMake(100.0f,100.0f) callback:^(UIImage *image){
    [imageView setImage:image];
}];
</code></pre>

<p>If the device has a non-retina display the <code>apple_logo.png</code> image will be rendered with a size of 100&#215;100. If the device has a retina display the <code>apple_logo@2x.png</code> image will be rendered with a size of 200&#215;200.</p>

<p>The example uses <a href="https://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/00_Introduction.html">blocks</a> and <a href="https://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html">ARC</a> but you could easily re-write it to support older iOS versions.</p>

<p>Now your distributed iOS app only has a small vector file but can render it to an iPhone sized non-retina PNG or a more massive iPad 3 retina PNG.</p>

<p><script src="https://gist.github.com/1955318.js"></script><noscript>
    //
    //  LoadImage.h
    //  AssetsFromPDF
    //
    //  Created by Jeffrey Sambells on 2012-03-02.
    //</p>

<pre><code>#import &lt;Foundation/Foundation.h&gt;

@interface LoadImage : NSObject

+ (void)LoadFromPDF:(NSString *)fileNameWithoutExtension size:(CGSize)size callback:(void (^)(UIImage *))callback;

@end


//
//  LoadImage.m
//  AssetsFromPDF
//
//  Created by Jeffrey Sambells on 2012-03-02.
//

#import "LoadImage.h"
#import "NSThread+Blocks.h"

@implementation LoadImage

+ (void)LoadFromPDF:(NSString *)fileNameWithoutExtension size:(CGSize)size callback:(void (^)(UIImage *))callback  {

    [NSThread performBlockInBackground:^{


        // Determine if the device is retina.
        BOOL isRetina = [UIScreen instancesRespondToSelector:@selector(scale)] &amp;&amp; [[UIScreen mainScreen] scale] == 2.0;


        // Create a file manager so we can check if the image exists and store the image.
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSFileManager *fileManger = [NSFileManager defaultManager];

        // Define the formats for the image names (low and high res).
        NSString *path = @"rendered-%@.png";
        NSString *pathHigh = @"rendered-%@@2x.png";

        // Get the file name.
        NSString *file = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:( isRetina ? pathHigh : path ) , fileNameWithoutExtension]];

        UIImage *image;

        if ( ![fileManger fileExistsAtPath:file] ) {

            // Image doesn't exist so load the PDF and create it.

            // Get a reference to the PDF.
            NSString *pdfName = [NSString stringWithFormat:@"%@.pdf", fileNameWithoutExtension];
            CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), (__bridge CFStringRef)pdfName, NULL, NULL);
            CGPDFDocumentRef pdfDoc = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
            CFRelease(pdfURL);

            if (isRetina) {
                UIGraphicsBeginImageContextWithOptions(size, false, 0); 
            } else {
                UIGraphicsBeginImageContext( size );
            }

            // Load the first page. You could have multiple pages if you wanted.
            CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDoc, 1);

            CGContextRef context = UIGraphicsGetCurrentContext();

            // PDF page drawing expects a lower-left coordinate system, 
            // flip the coordinate system before we start drawing.
            CGRect bounds = CGContextGetClipBoundingBox(context);
            CGContextTranslateCTM(context, 0, bounds.size.height);
            CGContextScaleCTM(context, 1.0, -1.0);

            // Save the graphics state.
            CGContextSaveGState(context);

            // CGPDFPageGetDrawingTransform provides an easy way to get the transform 
            // for a PDF page. It will scale down to fit, including any
            // base rotations necessary to display the PDF page correctly. 
            CGRect transformRect = CGRectMake(0, 0, size.width, size.height);
            CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, transformRect, 0, true);

            // And apply the transform.
            CGContextConcatCTM(context, pdfTransform);

            // Draw the page.
            CGContextDrawPDFPage(context, pdfPage);

            // Restore the graphics state.
            CGContextRestoreGState(context);

            // Generate the image.
            image = UIGraphicsGetImageFromCurrentImageContext();

            // Store the PNG for next time.
            [UIImagePNGRepresentation(image) writeToFile:file atomically:YES];

            UIGraphicsEndImageContext();
            CGPDFDocumentRelease(pdfDoc);   

        } else {

            // Load the image from the file system.
            image = [UIImage imageWithContentsOfFile:file];

        }

        [[NSThread mainThread] performBlock:^{
            callback(image);
        }];

    }];}

@end


//
//  NSThread+Blocks.h
//

#import &lt;Foundation/Foundation.h&gt;

@interface NSThread (BlocksAdditions)
- (void)performBlock:(void (^)())block;
- (void)performBlock:(void (^)())block waitUntilDone:(BOOL)wait;
+ (void)performBlockInBackground:(void (^)())block;
@end

//
//  NSThread+Blocks.m
//

#import "NSThread+Blocks.h"

@implementation NSThread (BlocksAdditions)

- (void)performBlock:(void (^)())block
{
    if ([[NSThread currentThread] isEqual:self])
        block();
    else
        [self performBlock:block waitUntilDone:NO];
}

- (void)performBlock:(void (^)())block waitUntilDone:(BOOL)wait
{
    [NSThread performSelector:@selector(ng_runBlock:)
                     onThread:self
                   withObject:[block copy]
                waitUntilDone:wait];
}

+ (void)ng_runBlockPool:(void (^)())block
{
    @autoreleasepool {
        block();
    }
}

+ (void)ng_runBlock:(void (^)())block
{
    block();
}

+ (void)performBlockInBackground:(void (^)())block
{
    [NSThread performSelectorInBackground:@selector(ng_runBlockPool:)
                               withObject:[block copy]];
}

@end
</code></pre>

<p></noscript></p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/03/02/beating-the-20mb-size-limit-ipad-retina-displays/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/03/02/beating-the-20mb-size-limit-ipad-retina-displays/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; #pragma]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/03/01/pragma/" />
		<id>http://jeffreysambells.com/?p=1565</id>
		<updated>2012-03-02T17:28:29Z</updated>
		<published>2012-03-01T18:41:48Z</published>
		<category scheme="http://jeffreysambells.com" term="Miscellaneous" />		<summary type="html"><![CDATA[In iOS source examples, you&#8217;ve probably come across the use of #pragma. Pragmas are directives which instruct the compiler to use pragmatic or implementation-dependent features. Xcode supports some of helpful pragmas that can help you organize and manage your code. #pragma mark A Heading The mark argument is probably the most common one you&#8217;ll see [...]<p><a href="http://jeffreysambells.com/posts/2012/03/01/pragma/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/03/01/pragma/"><![CDATA[<p>In iOS source examples, you&#8217;ve probably come across the use of <code>#pragma</code>. Pragmas are <a href="http://en.wikipedia.org/wiki/Directive_programming">directives</a> which instruct the compiler to use pragmatic or implementation-dependent features. Xcode supports some of helpful pragmas that can help you organize and manage your code.</p>

<h2><code>#pragma mark A Heading</code></h2>

<p>The <code>mark</code> argument is probably the most common one you&#8217;ll see used in Xcode. When added to your code it will give you a nice heading in the navigation bar as shown here:</p>

<p><figure><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2012/03/Xcode-Navigation-300x170.png" alt="" title="Xcode Navigation" /></figure></p>

<p>A mark with a dash (-) such as this:</p>

<pre><code>#pragma mark - A Heading
</code></pre>

<p>will include a divider line above the heading. Leave the dash out and you&#8217;ll just get the heading. You can also do something like this:</p>

<pre><code>#pragma mark -
#pragma mark A Heading
</code></pre>

<p>and you&#8217;ll get the same thing.</p>

<h2><code>#pragma unused(var)</code></h2>

<p>You should keep you code clean and ideally without unused variable but placing a <code>#pragma</code> with the <code>unused</code> argument after a variable lets you suppress those &#8220;unused variable&#8221; warnings you see far too often.</p>

<pre><code>BOOL test = YES;
#pragma unused(test)
</code></pre>

<h2><code>#pragma clang diagnostic</code></h2>

<p>(thanks to Guy Shaviv from <a href="http://tivstudio.com">tvistudio.com</a> for sending this in)</p>

<p>clang diagnostic is useful to get rid of those pesky warnings when performing a selector with ARC from a variable, and ARC doesn&#8217;t know if the selector returns a retained object or not.</p>

<h1>pragma clang diagnostic push</h1>

<h1>pragma clang diagnostic ignored &#8220;-Warc-performSelector-leaks&#8221;</h1>

<pre><code>           [obj performSelector:sel withObject:arg];
</code></pre>

<h1>pragma clang diagnostic pop</h1>

<h2>Some other directives</h2>

<p>While I&#8217;ve got your attention there two other useful directives you might want to try: <code>#warning</code> and <code>#error</code>. As you can guess, these generate warnings and error durring compile. Warning as especially useful for TODO items. I used to use a TODO comment to remind myself of TODO&#8217;s in the code:</p>

<pre><code>// TODO fix this.
</code></pre>

<p>but more often than not they were forgotten until moths later when a bug poped up and the line above read &#8216;// TODO fix this&#8217;. Instead, I use a #warning so that all the TODO&#8217;s are in the compiler warnings:</p>

<pre><code>#warning This is not complete
</code></pre>

<p>which generates:</p>

<p><figure><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2012/03/Xcode-Warning.png" alt="" title="Xcode Warning" /></figure></p>

<p>The #error directive does the same only it&#8217;s generates an error and halts the compile. This is useful in the case of a  preprocessor conditional</p>

<pre><code>#ifdef SOMETHING
    // Do stuff
#else
    #error SOMETHING was not defined!!!
#endif
</code></pre>

<p>If you know of any other neat #pragmas let me know and I&#8217;ll add them here.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/03/01/pragma/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/03/01/pragma/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; Everyone Fails]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/02/27/everyone-fails/" />
		<id>http://jeffreysambells.com/?p=1553</id>
		<updated>2012-02-27T21:24:13Z</updated>
		<published>2012-02-27T21:24:13Z</published>
		<category scheme="http://jeffreysambells.com" term="Miscellaneous" /><category scheme="http://jeffreysambells.com" term="failure" />		<summary type="html"><![CDATA[I think you have to fail to learn and get better at something. There’s really no way around it. The trick is to accept failure as a part of the process and know that by trying again, you’ll do just a little bit better. ~ Mark Jardine Always remembering that failure is a necessary part [...]<p><a href="http://jeffreysambells.com/posts/2012/02/27/everyone-fails/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/02/27/everyone-fails/"><![CDATA[<blockquote>
  <p>I think you have to fail to learn and get better at something. There’s really no way around it. The trick is to accept failure as a part of the process and know that by trying again, you’ll do just a little bit better.
  ~ <a href="http://ryancash.net/post/18143652473/mark-jardine-interview">Mark Jardine</a></p>
</blockquote>

<p>Always remembering that failure is a necessary part of the process will make you produce better things, live a better life and be an overall better person.</p>

<p>via <a href="http://tightwind.net/2012/02/ryan-cashs-interview-with-mark-jardine/">TightWind</a></p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/02/27/everyone-fails/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/02/27/everyone-fails/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; PlayBook&#8217;s LEET Web Inspector]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/02/23/playbooks-leet-web-inspector/" />
		<id>http://jeffreysambells.com/?p=1530</id>
		<updated>2012-02-23T21:52:32Z</updated>
		<published>2012-02-23T21:52:32Z</published>
		<category scheme="http://jeffreysambells.com" term="Miscellaneous" /><category scheme="http://jeffreysambells.com" term="PlayBook" /><category scheme="http://jeffreysambells.com" term="RIM" /><category scheme="http://jeffreysambells.com" term="Web Inspector" /><category scheme="http://jeffreysambells.com" term="WebKit" />		<summary type="html"><![CDATA[I&#8217;ve been playing with my new BlackBerry PlayBook for a day now and by far the most impressive feature I&#8217;ve come across is the PlayBook Browser&#8217;s web inspector. It&#8217;s awesome. RIM really raises the bar for every other mobile OS I&#8217;ve tried developing for. Trying to create and design mobile HTML5 apps has always been [...]<p><a href="http://jeffreysambells.com/posts/2012/02/23/playbooks-leet-web-inspector/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/02/23/playbooks-leet-web-inspector/"><![CDATA[<p>I&#8217;ve been <a href="http://twitter.com/search/realtime/iamamused%20%23playbook">playing with my new BlackBerry PlayBook</a> for a day now and by far the most impressive feature I&#8217;ve come across is the PlayBook Browser&#8217;s web inspector. It&#8217;s awesome. RIM really raises the bar for every other mobile OS I&#8217;ve tried developing for.</p>

<p>Trying to create and design mobile HTML5 apps has always been a pain in the ass to say the least. In iOS you&#8217;re basically flying blind. You can use Safari with a small window on the desktop to kind of simulate mobile safari but it&#8217;s just not the same&#8211;good luck debugging touch interaction. The PlayBook on the other hand gives you full access to the same WebKit web inspector we&#8217;ve come to love on the desktop. And it&#8217;s fully interactive.</p>

<p>To enable it you have to set up your PlayBook for development: Go to the PlayBook device&#8217;s Settings > Security and then select Development Mode. You&#8217;ll need to password protect the device to enable dev mode. Next, open the browser and swipe down from the top edge and select the browser&#8217;s Settings > Privacy and Security > Enable Web Inspector.</p>

<p>When enabled it will present you with an IP address. Write that down. Also, if you&#8217;re a true web developer you can probably appreciate RIM&#8217;s choice of port number.</p>

<p><strong>NOTE: with the web inspector enabled anyone on the same network will be able to access the inspector&#8217;s URL and thus be able to see the pages you&#8217;re looking at. Keep it disabled on a public network and don&#8217;t browse your banking site.</strong></p>

<p>Now go to your desktop&#8217;s web browser (which of course has to be on the same WiFi network) and enter that url. You&#8217;ll be presented with a link to the current browser page which will bring up the WebKit web inspector.</p>

<p><figure><img src="http://jeffreysambells.com/wordpress/wp-content/uploads/2012/02/Screen-Shot-2012-02-23-at-4.19.46-PM-1024x573.png" alt="" title="PlayBook Web Inspector" /></figure></p>

<p>Click and inspect anything your want content and keep an eye on your PlayBook, it will reflect any changes you make on-the-fly just the way your desktop web browser would. Now that some good stuff.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/02/23/playbooks-leet-web-inspector/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/02/23/playbooks-leet-web-inspector/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
		<entry>
		<author>
			<name>Jeffrey Sambells</name>
						<uri>http://JeffreySambells.com</uri>
					</author>
		<title type="html"><![CDATA[&#9734; Disable ARC in Xcode on a per-file basis]]></title>
		<link rel="alternate" type="text/html" href="http://jeffreysambells.com/posts/2012/02/21/disable-arc-in-xcode-on-a-per-file-basis/" />
		<id>http://jeffreysambells.com/?p=1547</id>
		<updated>2012-02-21T16:39:24Z</updated>
		<published>2012-02-21T16:39:24Z</published>
		<category scheme="http://jeffreysambells.com" term="Miscellaneous" />		<summary type="html"><![CDATA[Automatic Reference Counting (ARC) in the latest version of Xcode/Objective-C is awesome. I can&#8217;t count the number of times (see what I did there?) I&#8217;ve missed a release by accident. The only problem with ARC is that it has a hissy fit when you try to include libraries of code that are not ARC compliant. [...]<p><a href="http://jeffreysambells.com/posts/2012/02/21/disable-arc-in-xcode-on-a-per-file-basis/">&#9734; Permalink</a></p>]]></summary>
		<content type="html" xml:base="http://jeffreysambells.com/posts/2012/02/21/disable-arc-in-xcode-on-a-per-file-basis/"><![CDATA[<p><a href="http://clang.llvm.org/docs/AutomaticReferenceCounting.html">Automatic Reference Counting</a> (ARC) in the latest version of Xcode/Objective-C is awesome. I can&#8217;t count the number of times (see what I did there?) I&#8217;ve missed a <code>release</code> by accident. The only problem with ARC is that it has a hissy fit when you try to include libraries of code that are not ARC compliant. ARC does interoperate with manual reference counting code on a per-file basis so to fix it, just disable ARC for the files it&#8217;s complaining about. This way, some files can use arc while others don&#8217;t need to.</p>

<p>Just follow these steps to set the compiler flags and disable ARC on a file:</p>

<ul>
<li>Select your Project in the Xcode project tree (command 1).</li>
<li>Select your Target in the standard editor.</li>
<li>Select the Build Phases tab.</li>
<li>Expand the Compile Sources section.</li>
<li>Select one (or more) files you want to exclude from ARC.</li>
<li>Press the return key to open the Compiler Flags popup.</li>
<li>Add <code>-fno-objc-arc</code> to the compiler flags. </li>
<li>Select done (press the return key again)</li>
</ul>

<p>Now, each file you had selected will have the <code>-fno-objc-arc</code> compiler flag set and will not use ARC when compiled.</p>
]]></content>
		<link rel="replies" type="text/html" href="http://jeffreysambells.com/posts/2012/02/21/disable-arc-in-xcode-on-a-per-file-basis/#comments" thr:count="0" />
		<link rel="replies" type="application/atom+xml" href="http://jeffreysambells.com/posts/2012/02/21/disable-arc-in-xcode-on-a-per-file-basis/feed/atom/" thr:count="0" />
		<thr:total>0</thr:total>
	</entry>
	</feed><!-- Dynamic page generated in 2.696 seconds. --><!-- Cached page generated by WP-Super-Cache on 2012-05-26 01:28:52 -->

