<?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>Jeff Kelley’s Blog</title> <atom:link href="http://blog.slaunchaman.com/feed/" rel="self" type="application/rss+xml" /><link>http://blog.slaunchaman.com</link> <description>Mac tips, iPhone applications, and the like</description> <lastBuildDate>Fri, 02 Dec 2011 04:51:07 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>Enforcing iOS Security Settings in Third-Party Applications</title><link>http://blog.slaunchaman.com/2011/12/01/enforcing-ios-security-settings-in-third-party-applications/</link> <comments>http://blog.slaunchaman.com/2011/12/01/enforcing-ios-security-settings-in-third-party-applications/#comments</comments> <pubDate>Fri, 02 Dec 2011 04:51:07 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[iOS Programming]]></category> <category><![CDATA[Programming Tips]]></category> <category><![CDATA[App Store]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Cocoa Touch]]></category> <category><![CDATA[configuration profiles]]></category> <category><![CDATA[hacks]]></category> <category><![CDATA[OpenSSL]]></category> <category><![CDATA[programming]]></category> <category><![CDATA[security]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=478</guid> <description><![CDATA[A while back, I was working on an  application for a client with a very specific requirement. Since it collected personal data, the application could only run on iOS devices that were protected with a passcode. This requirement, seemingly very simple from the client’s perspective, was a bit of a hassle to implement on the [...]]]></description> <content:encoded><![CDATA[<p>A while back, I was working on an  application for a client with a very specific requirement. Since it collected personal data, the application could only run on iOS devices that were protected with a passcode. This requirement, seemingly very simple from the client’s perspective, was a bit of a hassle to implement on the programming side of things. There’s no simple method on <code>UIDevice</code> to determine if a passcode is set, nor is there a way to force that programatically. In fact, there’s no way to force most things like that. The iOS device isn’t the programmer’s, it’s the user’s. Except when it isn’t.</p><p>One of the things that you <em>can</em> do is to use the <a
title="Apple - Support - iPhone - Enterprise" href="http://www.apple.com/support/iphone/enterprise/">iPhone Configuration Utility</a> to make a configuration profile. These profiles can support a range of things, from requiring a passcode (or even an advanced, non-numeric passcode) to WiFi settings, VPN to CardDAV settings. Creating a configuration profile that requires a passcode, then installing that configuration profile onto the device is a no-brainer. But how do you ensure that the application will only run in that case?</p><p><strong>Disclaimer:</strong> Before I go any further, you should know that since this was an in-house project, none of the code that I wrote made it into the App Store. Therefore, I don’t know if this is kosher in an App Store app, nor do I recommend this approach for that.</p><p>One thing that you <em>can</em> do is to include a self-signed certificate in a configuration profile. Those of you familiar with OpenSSL may be groaning as you realize where this horrible, horrible workaround is headed. I created a new certificate authority. With that new certificate authority, I signed a separate certificate that I had created. Verifying this certificate, then, requires that the verifying party accept the certificate authority’s certificate as valid. Well, since you can set that in the configuration profile, I did, along with the passcode requirement. Then, in the app, I bundled the certificate that I had signed with my CA.</p><p>When the app starts up, it attempts to verify the certificate. In the case where the configuration profile is installed and the CA’s certificate is in the system’s keychain as trusted, this is no problem: the certificate checks out and my app is free to go. If that validation fails, however, then I know that the certificate from the CA is in the system, so I know that the configuration profile is installed, as well.</p><p>Why this works for a passcode so well is that to install a configuration profile on a device without a passcode when the profile requires one is that <em>you can’t install it without setting a passcode in the process.</em> For the client, this was Good Enough, and the app shipped and worked properly. It’s worth noting, though, that the less the end-user knows about this process, the better. To circumvent the passcode restriction, all one would have to do would be to modify the configuration profile to still include the CA’s certificate, but <em>not</em> the pas code requirement. For that reason I can’t recommend this for anything like EMR or tax records, but for minor demographic information like we were collecting, this sufficed.</p><p>I realize this didn’t include any code, but the individual portions aren’t that hard, and I don’t have access to the original code so I’d have to re-write them all. Here they are in a nicely-formatted list for those keeping score at home:</p><ol><li>Create a new certificate authority with OpenSSL.</li><li>Create a new certificate, then sign it with that certificate authority you just created.</li><li>Create a configuration profile in the iTunes Configuration Utility with the settings you would like to enforce.</li><li>In the “Credentials” section in the iTunes Configuration Utility, add your CA’s public-facing certificate to the configuration profile.</li><li>Add the certificate you signed with your CA to your application’s bundle.</li><li>In your application, verify the certificate you included.</li><li>Distribute the configuration profile along with your application to end users.</li></ol><p>Like I said, this is far from perfect. But when you’re working with an enterprise client who has Big Needs, this is one trick to keep in your back pocket when you’re up against a deadline.</p> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/12/01/enforcing-ios-security-settings-in-third-party-applications/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Steve Jobs</title><link>http://blog.slaunchaman.com/2011/10/05/steve-jobs/</link> <comments>http://blog.slaunchaman.com/2011/10/05/steve-jobs/#comments</comments> <pubDate>Thu, 06 Oct 2011 02:04:49 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[Miscellania]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=471</guid> <description><![CDATA[Without Steve Jobs, I wouldn’t be doing what I am today. Who knows what it would be, but chances are that I wouldn’t be nearly as fulfilled as I am. He brought about several technological revolutions, and his vision may never be matched. Here’s one of my favorite Steve Jobs quotes: When you’re young, you [...]]]></description> <content:encoded><![CDATA[<p>Without Steve Jobs, I wouldn’t be doing what I am today. Who knows what it would be, but chances are that I wouldn’t be nearly as fulfilled as I am. He brought about several technological revolutions, and his vision may never be matched. Here’s one of my favorite Steve Jobs quotes:</p><blockquote><p><em>When you’re young, you look at television and think, There’s a conspiracy. The networks have conspired to dumb us down. But when you get a little older, you realize that’s not true. The networks are in business to give people exactly what they want. That’s a far more depressing thought.</em></p></blockquote><p>Rest in peace, Steve.</p> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/10/05/steve-jobs/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Cocoa Touch: Circumventing UITableViewCell Redraw Issues with Multithreading</title><link>http://blog.slaunchaman.com/2011/08/14/cocoa-touch-circumventing-uitableviewcell-redraw-issues-with-multithreading/</link> <comments>http://blog.slaunchaman.com/2011/08/14/cocoa-touch-circumventing-uitableviewcell-redraw-issues-with-multithreading/#comments</comments> <pubDate>Sun, 14 Aug 2011 20:14:23 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[iOS Programming]]></category> <category><![CDATA[Programming Tips]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Cocoa Touch]]></category> <category><![CDATA[iOS]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[multithreading]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[programming]]></category> <category><![CDATA[tips]]></category> <category><![CDATA[UITableViewCell]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=467</guid> <description><![CDATA[In your career as a Cocoa or Cocoa Touch developer, every now and then you’ll encounter an issue with something Apple has written. Whether it’s a full-blown bug, something that doesn’t work quite how you’d expect it to, or a minor inconvenience, it happens. When it does, naturally the first thing you do is file [...]]]></description> <content:encoded><![CDATA[<p>In your career as a Cocoa or Cocoa Touch developer, every now and then you’ll encounter an issue with something Apple has written. Whether it’s a full-blown bug, something that doesn’t work quite how you’d expect it to, or a minor inconvenience, it happens. When it does, naturally the first thing you do is file <a
href="http://bugreport.apple.com">a bug report</a> (<em>right?</em>). After that, though, you need to <em>do something</em> about it. This usually occurs right when a project is due, so often we can’t wait for Apple’s engineering teams to fix the problems (or tell you that you’re wrong). This post is an example of using KVO to get around the problem without worrying about it anymore.</p><p><strong>The Problem:</strong> In iOS, if you create a <code>UITableViewCell</code> and return it to the table view in its data source’s <code>-tableView:cellForRowAtIndexPath:</code> method, but then return later (say, after doing some background processing) to add an image to the cell’s <code>imageView</code>, you don’t see anything! Why? Well, it looks like either the image view isn’t added to the cell’s view hierarchy if you don’t immediately add an image or there’s some other bug in the <code>UITableViewCell</code> implementation. I don’t think it’s a bug, I think it’s just a side effect of an optimization; if there’s no image, why add it to the cell?</p><p>So how do we fix it? Well, a simple call to <code>-setNeedsLayout</code> gets the cell to fix itself quite nicely. But we shouldn’t have to do that from our table view data source—that has a bit of code smell to it. Lines like that quickly get overused, with programmers calmly stating, “I don’t know why, but we always do that.” No, a better solution is to get the cell to handle this problem on its own.</p><p>We’ll create a subclass of UITableViewCell and use KVO. When we create the cell, we’ll register for KVO notifications with the on the image view whenever its <code>image</code> property is modified—but we’ll send the option to include the <em>old</em> value in the change dictionary. When we receive the notification, we’ll look at that dictionary, and if the old value was <code>nil</code>, then we’ll send <code>self</code> a <code>-setNeedsLayout</code> message. This avoids having to do it in other classes, and only does it when necessary. We simply set it and forget it.</p><div
id="gist-1143494" class="gist"><div
class="gist-file"><div
class="gist-data gist-syntax"><div
class="highlight"><pre><div class='line' id='LC1'><span class="cp">#import &lt;UIKit/UIKit.h&gt;</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'><span class="k">@interface</span> <span class="nc">JKTableViewCell</span> : <span class="nc">UITableViewCell</span></div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'><span class="k">@end</span></div><div class='line' id='LC7'><br/></div></pre></div></div><div
class="gist-meta"> <a
href="https://gist.github.com/raw/1143494/a53db908610a1504ee6b7b9cc120fa0a39e68e0e/JKTableViewCell.h" style="float:right;">view raw</a> <a
href="https://gist.github.com/1143494#file_jk_table_view_cell.h" style="float:right;margin-right:10px;color:#666">JKTableViewCell.h</a> <a
href="https://gist.github.com/1143494">This Gist</a> brought to you by <a
href="http://github.com">GitHub</a>.</div></div><div
class="gist-file"><div
class="gist-data gist-syntax"><div
class="highlight"><pre><div class='line' id='LC1'><span class="cp">#import &quot;JKTableViewCell.h&quot;</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'><span class="k">@implementation</span> <span class="nc">JKTableViewCell</span></div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'><span class="k">-</span> <span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nf">initWithStyle:</span><span class="p">(</span><span class="n">UITableViewCellStyle</span><span class="p">)</span><span class="nv">style</span> <span class="nf">reuseIdentifier:</span><span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">reuseIdentifier</span></div><div class='line' id='LC7'><span class="p">{</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">self</span> <span class="o">=</span> <span class="p">[</span><span class="n">super</span> <span class="nl">initWithStyle:</span><span class="n">style</span> <span class="nl">reuseIdentifier:</span><span class="n">reuseIdentifier</span><span class="p">];</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[[</span><span class="n">self</span> <span class="n">imageView</span><span class="p">]</span> <span class="nl">addObserver:</span><span class="n">self</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nl">forKeyPath:</span><span class="s">@&quot;image&quot;</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nl">options:</span><span class="n">NSKeyValueObservingOptionOld</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nl">context:</span><span class="nb">NULL</span><span class="p">];</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="n">self</span><span class="p">;</span></div><div class='line' id='LC18'><span class="p">}</span></div><div class='line' id='LC19'><br/></div><div class='line' id='LC20'><span class="c1">// The reason we’re observing changes is that if you create a table view cell, return it to the</span></div><div class='line' id='LC21'><span class="c1">// table view, and then later add an image (perhaps after doing some background processing), you</span></div><div class='line' id='LC22'><span class="c1">// need to call -setNeedsLayout on the cell for it to add the image view to its view hierarchy. We</span></div><div class='line' id='LC23'><span class="c1">// asked the change dictionary to contain the old value because this only needs to happen if the</span></div><div class='line' id='LC24'><span class="c1">// image was previously nil.</span></div><div class='line' id='LC25'><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">observeValueForKeyPath:</span><span class="p">(</span><span class="n">NSString</span> <span class="o">*</span><span class="p">)</span><span class="nv">keyPath</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nf">ofObject:</span><span class="p">(</span><span class="kt">id</span><span class="p">)</span><span class="nv">object</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nf">change:</span><span class="p">(</span><span class="n">NSDictionary</span> <span class="o">*</span><span class="p">)</span><span class="nv">change</span></div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nf">context:</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="nv">context</span></div><div class='line' id='LC29'><span class="p">{</span></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="n">object</span> <span class="o">==</span> <span class="p">[</span><span class="n">self</span> <span class="n">imageView</span><span class="p">]</span> <span class="o">&amp;&amp;</span></div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[</span><span class="n">keyPath</span> <span class="nl">isEqualToString:</span><span class="s">@&quot;image&quot;</span><span class="p">]</span> <span class="o">&amp;&amp;</span></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">([</span><span class="n">change</span> <span class="nl">objectForKey:</span><span class="n">NSKeyValueChangeOldKey</span><span class="p">]</span> <span class="o">==</span> <span class="nb">nil</span> <span class="o">||</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[</span><span class="n">change</span> <span class="nl">objectForKey:</span><span class="n">NSKeyValueChangeOldKey</span><span class="p">]</span> <span class="o">==</span> <span class="p">[</span><span class="n">NSNull</span> <span class="n">null</span><span class="p">]))</span> <span class="p">{</span></div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">[</span><span class="n">self</span> <span class="n">setNeedsLayout</span><span class="p">];</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC36'><span class="p">}</span></div><div class='line' id='LC37'><br/></div><div class='line' id='LC38'><span class="k">@end</span></div><div class='line' id='LC39'><br/></div></pre></div></div><div
class="gist-meta"> <a
href="https://gist.github.com/raw/1143494/90294445f0b984f4f823911404a14dca57d652ad/JKTableViewCell.m" style="float:right;">view raw</a> <a
href="https://gist.github.com/1143494#file_jk_table_view_cell.m" style="float:right;margin-right:10px;color:#666">JKTableViewCell.m</a> <a
href="https://gist.github.com/1143494">This Gist</a> brought to you by <a
href="http://github.com">GitHub</a>.</div></div></div> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/08/14/cocoa-touch-circumventing-uitableviewcell-redraw-issues-with-multithreading/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>GCD Example Updated (Now With More Speed!)</title><link>http://blog.slaunchaman.com/2011/08/12/gcd-example-updated-now-with-more-speed/</link> <comments>http://blog.slaunchaman.com/2011/08/12/gcd-example-updated-now-with-more-speed/#comments</comments> <pubDate>Sat, 13 Aug 2011 04:03:57 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[iOS Programming]]></category> <category><![CDATA[Programming Tips]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Cocoa Touch]]></category> <category><![CDATA[Grand Central Dispatch]]></category> <category><![CDATA[iOS]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[meta]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[open-source]]></category> <category><![CDATA[performance]]></category> <category><![CDATA[programming]]></category> <category><![CDATA[UIImage]]></category> <category><![CDATA[updates]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=463</guid> <description><![CDATA[Due to popular demand, I’ve updated my GCD example from previous talks to include a few things to make the example not only do something on a background queue, but also snappy. It should scroll much better now. A quick rundown of what changed: Images are now resized. Since the example uses wallpaper-sized images, there’s [...]]]></description> <content:encoded><![CDATA[<p>Due to popular demand, I’ve updated <a
href="https://github.com/SlaunchaMan/GCDExample">my GCD example</a> from previous talks to include a few things to make the example not only do something on a background queue, but also snappy. It should scroll much better now. A quick rundown of what changed:</p><ul><li><strong>Images are now resized.</strong> Since the example uses wallpaper-sized images, there’s no sense in <em>not</em> resizing them to go on a 44-pixel-tall table view cell. I’m using the popular image-resizing routines from <a
href="http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/" target="_blank">Trevor’s Bike Shed</a> to do the resizing with a nice interpolation quailty.</li><li><strong>Those resized images are now cached.</strong> I use an <code>NSCache</code> to store the images. If the app receives a memory warning, it’ll jettison all of the cached images, but if you’re just scrolling up and down this is a quick and dirty way to cache the images. I had never really used <code>NSCache</code> before, so this was a good excuse to try it.</li></ol><p>I’m at <a
href="http://www.cocoaconf.com" target="_blank">CocoaConf</a> in that state down to the South today, so this post has been brought to you by late-night hotel room caffeine. I made some other changes to the project to deal with a weird table view cell bug that I’ve submitted to Apple; a post on that is coming up next!</p> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/08/12/gcd-example-updated-now-with-more-speed/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Asynchronous Synchronous Requests: Effortless Networking Code</title><link>http://blog.slaunchaman.com/2011/07/19/asynchronous-synchronous-requests-effortless-networking-code/</link> <comments>http://blog.slaunchaman.com/2011/07/19/asynchronous-synchronous-requests-effortless-networking-code/#comments</comments> <pubDate>Tue, 19 Jul 2011 21:50:36 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[Programming Tips]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[ASIHTTPRequest]]></category> <category><![CDATA[C]]></category> <category><![CDATA[Grand Central Dispatch]]></category> <category><![CDATA[iOS]]></category> <category><![CDATA[Mac OS X]]></category> <category><![CDATA[NSURLConnection]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[performance]]></category> <category><![CDATA[tips]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=457</guid> <description><![CDATA[Today I showed a couple of people at work a technique I use to do asynchronous URL loading in iOS, and the response on Twitter was great, so I’ve written it up for everybody. If you’re used to using ASIHTTPRequest or rolling your own NSURLConnection delegates, hopefully this method will be a breath of fresh [...]]]></description> <content:encoded><![CDATA[<p>Today I showed a couple of people at work a technique I use to do asynchronous URL loading in iOS, and the response on Twitter was great, so I’ve written it up for everybody. If you’re used to using <code>ASIHTTPRequest</code> or rolling your own <code>NSURLConnection</code> delegates, hopefully this method will be a breath of fresh air.</p><p><strong>The Problem:</strong> When you want to load something from the Internet, you don’t want to block your UI—especially when iOS might just kill your app for doing so—but writing delegate code is a pain. You have to remember which delegate methods get called in what order, to set yourself as the delegate (can’t tell you how many times that’s tripped me up), and handling multiple simultaneous connections with one delegate is… tricky, at best.</p><p><strong>The Solution</strong>: Use Grand Central Dispatch. Maybe I just love GCD too much and this is me seeing everything as a nail, but let’s look at the following code for loading a URL:</p><pre class="brush: objc; title: ; notranslate">- (void)loadAwesomeURL
{
    NSString *awesomeURI = @&quot;http://www.awesomeexample.com/?output=JSON&quot;;
    NSURL *awesomeURL = [NSURL URLWithString:awesomeURI];
    NSURLRequest *awesomeRequest = [NSURLRequest requestWithURL:awesomeURL];
    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:awesomeRequest
                                                                     delegate:self];
    [theConnection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [myMutableData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self processTheAwesomeness];
}</pre><p>That sucks. Three methods, and I didn’t even do any error handling! There has to be a better way. <code>NSURLConnection</code> offers a synchronous method, but everybody <em>knows</em> you don’t use it… so let’s do exactly that. But since we want to make this asynchronous, we’ll use Grand Central Dispatch to wrap it in a <code>dispatch_async()</code> call:</p><pre class="brush: objc; title: ; notranslate">- (void)loadAwesomeURL
{
    NSString *awesomeURI = @&quot;http://www.awesomeexample.com/?output=JSON&quot;;
    NSURL *awesomeURL = [NSURL URLWithString:awesomeURI];
    NSURLRequest *awesomeRequest = [NSURLRequest requestWithURL:awesomeURL];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        NSURLResponse *response = nil;
        NSError *error = nil;
        NSData *receivedData = [NSURLConnection sendSynchronousRequest:awesomeRequest
                                                     returningResponse:&amp;response
                                                                 error:&amp;error];
        [self processTheAwesomeness];
    });
}</pre><p>We can easily do error checking after the <code>NSURLConnection</code> call; simply check to see if <code>receivedData</code> is <code>nil</code>, cast <code>response</code> to an <code>NSHTTPURLRequest</code> and check its <code>statusCode</code> property, and if all else fails, check out <code>error</code>.</p><p><strong>Note:</strong> I’ve received a fair amount of negative feedback on this article on Twitter, Reddit, and in the comments, and I feel like I ought to make a few points clear:</p><ul><li>This is not the last networking solution you’ll ever need. Among other things, this does not support:<ol><li>Canceling the connection</li><li>Running code when the connection is half-done</li><li>Streaming data to a file for large downloads</li></ol></li><li>This is a quick example. It’s mainly designed to illustrate <code>dispatch_async()</code> as a wrapper for synchronous APIs.</li><li>It isn’t good for multiple connections. You’ll want a custom dispatch queue for that.<li>It doesn’t run on the main thread. If you’re updating your UI, you’ll need to do that on the main thread.</li></ol> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/07/19/asynchronous-synchronous-requests-effortless-networking-code/feed/</wfw:commentRss> <slash:comments>14</slash:comments> </item> <item><title>What Every Designer Should Know About iOS</title><link>http://blog.slaunchaman.com/2011/07/17/what-every-designer-should-know-about-ios/</link> <comments>http://blog.slaunchaman.com/2011/07/17/what-every-designer-should-know-about-ios/#comments</comments> <pubDate>Sun, 17 Jul 2011 17:54:55 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[Programming Tips]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[design]]></category> <category><![CDATA[iOS]]></category> <category><![CDATA[tips]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=450</guid> <description><![CDATA[Working with designers over the years, I’ve seen a few areas where the world of a designer and the world of a developer merge very well, and a few areas where they don’t. Photoshop comps that lead to sliced assets with non-localized text on them, storing a vertical gradient in a 1,024 × 1,024 JPEG [...]]]></description> <content:encoded><![CDATA[<p>Working with designers over the years, I’ve seen a few areas where the world of a designer and the world of a developer merge very well, and a few areas where they don’t. Photoshop comps that lead to sliced assets with non-localized text on them, storing a vertical gradient in a 1,024 × 1,024 JPEG image, Retina Display graphics that don’t match up to their non-Retina Display versions, and other places where I feel that a little bit of knowledge about iOS would go a long way. So, I’ve prepared this piece on what every designer should know before working with an iOS project.</p><ol><li><strong>Apple Controls Everything.</strong><br/>Literally. Since there’s no getting around this fact, we might as well start with it now. When your developer works with iOS, she’s using Apple’s tools to run on Apple’s operating system. So when she tells you that, for instance, a navigation bar can accept a tint color but not a custom gradient or an image, that’s because the Apple-provided version has those restrictions. Normally this isn’t an issue, but a designer needs to be prepared to provide their art in several different formats. For a tab bar, for instance, icons need to be (around) 30 × 30 pixels and filled out in the alpha channel.</li><p><br/></p><li><strong>The Retina Display is <em>not</em> for layout.</strong><br/>I think the best example of my last point above is the Retina Display. When it came out, developers started asking their designers for double-sized versions of their assets. Every image you provided for the original product needed to be resized. But the important thing to note about the Retina Display for a designer is not that suddenly there are two screen sizes to worry about on the iPhone. In fact, that can lead to catastrophe. When you design for the iPhone, you still create according to a 320 × 480 <em>point</em> screen. The Retina Display, unlike the regular display, happens to have two pixels per point. So when you make your assets, you have to <em>design</em> around the smaller size, but then take your assets and make a version <em>exactly</em> twice as large. This needs to be exact because the developer isn’t specifying the double-sized art or layout—in fact, they don’t specify anything. The art is simply named with an <code>@2x</code> suffix and iOS loads it in automatically.</li><p><br/></p><li><strong>Things Change.</strong><br/>When the Retina Display came out, that was a big change for designers (and developers). Apple can do this at any time. Tomorrow morning, Apple could announce a new iPhone Nano with a smaller screen or an iPad Pro with a Retina Display screen. If the screen size changes beyond a certain threshold, then developers will need to re-work their applications’ UI to accomodate. If that happens, your developer will be asking you for new assets, and he’ll want them immediately. If you saved everything in Photoshop six months ago and forgot what exactly you did to style everything, it’s going to be a long week. That’s why I recommend working in vector art for all but the most photorealistic elements (like skeuomorphism). If your work is in vector art and the developer suddenly needs assets at 150% of the original size, you re-export as .PNG, send it to the developer, and go back to doing whatever it is designers do in their free time.</li><p><br/></p><li><strong>Push Your Developer.</strong><br/>iOS has very sophisticated drawing abilities. If you want the background of a certain UI element to have a gradient, you might generate that gradient at the size of the element, then send it to the developer. If you know that the gradient can be stretched horizontally, you might send a one-pixel-wide version of it, instead. But you can also just tell the developer, “Draw a gradient from this color to this color and use it here.” This applies to more advanced drawing as well—need a circle with a dark-blue fill at 80% opacity, stroked with a 3-point thick, white line? The developer can draw it in code. This has the advantage of working at any resolution and being extremely changeable. Decide tomorrow morning that you want the color of the circle a bit lighter? Instead of sending the developer a new image, send him a new color and have him draw it differently. I called this tip “push your developer” because not every developer is as comfortable as the next with more advanced drawing, but I firmly believe that the more drawing you can do in code, the better.</li><p><br/></p><li><strong>Spend Time on the Icon.</strong><br/>The app’s icon is the first thing a user sees when they’re browsing the App Store. A beautiful, well-conceived icon can do wonders for an app. There are plenty of resources online for iOS icon design, so if you’re not sure where to begin, just head to Google.</li><p><br/></p><li><strong>Standards are High.</strong><br/>The most successful iOS applications have a level of beauty to them that other apps just can’t match. Utilitarian layouts with spartan design work, and if your client is an enterprise looking for an internal app, are appropriate, but won’t help the app. Your goal should be to make the app successful <em>because</em> of your design, not in spite of it.</li></ol> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/07/17/what-every-designer-should-know-about-ios/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>Fun With the Objective-C Runtime: Run Code at Deallocation of Any Object</title><link>http://blog.slaunchaman.com/2011/04/11/fun-with-the-objective-c-runtime-run-code-at-deallocation-of-any-object/</link> <comments>http://blog.slaunchaman.com/2011/04/11/fun-with-the-objective-c-runtime-run-code-at-deallocation-of-any-object/#comments</comments> <pubDate>Tue, 12 Apr 2011 01:25:20 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[Mac Programming]]></category> <category><![CDATA[Programming Tips]]></category> <category><![CDATA[associated objects]]></category> <category><![CDATA[Blocks]]></category> <category><![CDATA[iOS]]></category> <category><![CDATA[Mac OS X]]></category> <category><![CDATA[memory management]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[Objective-C Runtime]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=428</guid> <description><![CDATA[Sometimes when you’re debugging an application, especially one that you’ve inherited, you find yourself wondering when an object is released. Autorelease pools only compound the problem, delaying the actual release until the run loop is idle. In this post, I’ll show you how to take advantage of new features in the Objective-C runtime to run [...]]]></description> <content:encoded><![CDATA[<p>Sometimes when you’re debugging an application, especially one that you’ve inherited, you find yourself wondering when an object is released. Autorelease pools only compound the problem, delaying the actual release until the run loop is idle. In this post, I’ll show you how to take advantage of new features in the Objective-C runtime to run arbitrary code when any object—whether it’s your own or a part of Apple’s frameworks—is deallocated.</p><p>We’ll be taking advantage of the Objective-C runtime’s new associated objects behavior. When you associate an object with another object using retain or copy semantics, the runtime automatically handles releasing it at the appropriate time. So, if we want one object to be released when another object is deallocated, we simply associate them:</p><pre class="brush: objc; gutter: false; title: ; notranslate">id objectToBeDeallocated;
id objectWeWantToBeReleasedWhenThatHappens;
objc_setAssociatedObject(objectToBeDeallocted,
                         &quot;someUniqueKey&quot;,
                         objectWeWantToBeReleasedWhenThatHappens,
                         OBJC_ASSOCIATION_RETAIN);</pre><p>Now, when <code>objectToBeDeallocated</code> is deallocated, <code>objectWeWantToBeReleasedWhenThatHappens</code> will be sent a <code>-release</code> message automatically. The association policy passed as the last parameter to the function can be one of the following:</p><table
border="0"><tbody><tr><td><code>OBJC_ASSOCIATION_ASSIGN</code></td><td>No memory management; the value is simply assigned.</td></tr><tr><td><code>OBJC_ASSOCIATION_RETAIN_NONATOMIC</code></td><td>Retains the object non-atomically.</td></tr><tr><td><code>OBJC_ASSOCIATION_COPY_NONATOMIC</code></td><td>Copies the object non-atomically.</td></tr><tr><td><code>OBJC_ASSOCIATION_RETAIN</code></td><td>Retains the object atomically.</td></tr><tr><td><code>OBJC_ASSOCIATION_COPY</code></td><td>Copies the object atomically.</td></tr></tbody></table><p>Obviously, using <code>OBJC_ASSOCIATION_ASSIGN</code> won’t work for us, since it won’t cause the object to be retained. We also don’t want to use either of the copy policies, since we only want one copy of our objects around. For this example I’ll be using <code>OBJC_ASSOCIATION_RETAIN</code>, but not over <code>OBJC_ASSOCIATION_RETAIN_NONATOMIC</code> for any compelling reason.</p><p>Now that we know how to release an object when another is deallocated, we need to create an object to run arbitrary code at deallocation time. Blocks are an excellent tool for this, so I created a dead-simple class, JKBlockExecutor, to handle the running of the block:</p><pre class="brush: objc; title: ; notranslate">typedef void (^voidBlock)(void);
@interface JKBlockExecutor : NSObject {
	voidBlock	block;
}
@property (nonatomic, readwrite, copy) voidBlock	block;
- (id)initWithBlock:(voidBlock)block;
@end
@implementation JKBlockExecutor
@synthesize block;
- (id)initWithBlock:(voidBlock)aBlock
{
	self = [super init];
	if (self) {
		block = Block_copy(aBlock);
	}
	return self;
}
- (void)dealloc
{
	if (block != nil) {
		block();
		Block_release(block);
	}
	[super dealloc];
}
@end</pre><p>Now that we can pass arbitrary code to a JKBlockExecutor (and if you have a better name I’m all ears), we can make a category on NSObject to make the association for us:</p><pre class="brush: objc; title: ; notranslate">const char *runAtDeallocBlockKey = &quot;JK__RunAtDeallocBlock&quot;;
@interface NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block;
@end
@implementation NSObject (JK_RunAtDealloc)
- (void)runAtDealloc:(voidBlock)block
{
	if (block) {
		JKBlockExecutor *executor = [[JKBlockExecutor alloc] initWithBlock:block];
		objc_setAssociatedObject(self,
								 (void *)runAtDeallocBlockKey,
								 executor,
								 OBJC_ASSOCIATION_RETAIN);
		[executor release];
	}
}
@end</pre><p>So, how do you use it? The following example prints &#8220;Deallocating foo!&#8221; when <code>foo</code> is deallocated:</p><pre class="brush: objc; title: ; notranslate">NSObject *foo = [[NSObject alloc] init];
[foo runAtDealloc:^{
	NSLog(@&quot;Deallocating foo!&quot;);
}];
[foo release];</pre><p>And that’s all there is to it!</p><p>Well, almost. There is one gotcha that I must warn you about: don’t access the object from within the block. There are two reasons. First, I’m not sure where in the deallocation process the Objective-C runtime releases its associated objects, so accessing the object may result in a crash. Second, if you reference the object from within the block, the block will retain the object. This causes a retain cycle where the block and the object each own each other, so neither will ever be released. If you absolutely must reference your object (at your own risk), then do it like so:</p><pre class="brush: objc; title: ; notranslate">NSObject *foo = [[NSObject alloc] init];
__block id objectRef = foo;
[foo runAtDealloc:^{
	NSLog(@&quot;Deallocating foo at address %p!&quot;, objectRef);
}];
[foo release];</pre><p>Using the <code>__block</code> storage qualifier on an Objective-C object causes the runtime to avoid retaining the object, since the dymanics of object retain counts inside of blocks would be far too hairy to manage automatically. Seriously, though: don’t do it unless you absolutely must.</p><p>So there you have it: a quick and dirty category on NSObject to run arbitrary code at deallocation. I don’t really see a use it for it in production code, but on those occasions when you’re debugging someone else’s memory management, this could be handy. Since it uses blocks and associated objects, you’ll need to be running Mac OS X Snow Leopard (64-bit) or later or iOS 4.0 or later.</p> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/04/11/fun-with-the-objective-c-runtime-run-code-at-deallocation-of-any-object/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Apple Surveying 32-Bit Third-Party Kernel Extensions</title><link>http://blog.slaunchaman.com/2011/03/22/apple-surveying-32-bit-third-party-kernel-extensions/</link> <comments>http://blog.slaunchaman.com/2011/03/22/apple-surveying-32-bit-third-party-kernel-extensions/#comments</comments> <pubDate>Wed, 23 Mar 2011 04:05:44 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[Systems Administration]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Kernel Extensions]]></category> <category><![CDATA[Mac OS X]]></category> <category><![CDATA[privacy]]></category> <category><![CDATA[security]]></category> <category><![CDATA[updates]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=424</guid> <description><![CDATA[Today I noticed something new in my LaunchDaemons folder: /Library/LaunchDaemons/com.apple.third_party_32b_kext_logger.plist. It starts a Ruby script (/usr/libexec/third_party_32b_kext_logger.rb) when your Mac starts up that (and I could be totally wrong, as I don’t know Ruby) appears to use /usr/sbin/kextfind -system-extensions to identify third-party kernel extensions (e.g. kernel extensions for which the identifier does not begin with com.apple) [...]]]></description> <content:encoded><![CDATA[<p>Today I noticed something new in my LaunchDaemons folder: <code>/Library/LaunchDaemons/com.apple.third_party_32b_kext_logger.plist</code>. It starts a Ruby script (<code>/usr/libexec/third_party_32b_kext_logger.rb</code>) when your Mac starts up that (and I could be totally wrong, as I don’t know Ruby) appears to use <code>/usr/sbin/kextfind -system-extensions</code> to identify third-party kernel extensions (e.g. kernel extensions for which the identifier does not begin with com.apple) that exist only in i386 or PPC forms. It makes sense why Apple would do this, as a move to 64-bit only would be in keeping with their typical attitude on leaving old hardware platforms behind, but this particular file is odd in that it’s in <code>/Library/LaunchDaemons</code> and not <code>/System/Library/LaunchDaemons</code>, where most Apple-created jobs are. Maybe this was a task given to a programmer new at Apple who was unfamiliar with the typical folder hierarchy on a Mac, but this smells odd. The only result I found for it in Google was <a
href="http://discussions.apple.com/thread.jspa?threadID=2791807">this Apple Support forum post</a>.<br
/> So, I did some investigation, and found that it uses the domain &#8220;com.apple.kexts.32bitonly&#8221; with the <code>defaults</code> command, and in my system log is this line:</p><blockquote><p><code>/var/log/system.log:Mar 22 19:31:30 Jeff-Kelleys-MacBook defaults[3439]: \nThe domain/default pair of (com.apple.kexts.32bitonly, lastRan) does not exist</code></p></blockquote><p>That is reason enough for me to believe that it’s installed as a part of Mac OS X 10.6.7, as that message signifies its last run time (the script quits if it’s been less than a week since it last ran). So, being the diligent former sysadmin that I am, I looked at the 10.6.7 update’s files, and didn’t see anything (else) of note. I don’t see a point in the script that reports this to Apple, so I don’t know if this constitutes a breach of privacy on their part, but it’s interesting nonetheless that it would appear that Apple is gauging whether or not they can leave 32-bit kernel extensions behind with minimal customer fuss.</p> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/03/22/apple-surveying-32-bit-third-party-kernel-extensions/feed/</wfw:commentRss> <slash:comments>17</slash:comments> </item> <item><title>iOS Programming for Multicore Processors</title><link>http://blog.slaunchaman.com/2011/03/03/ios-programming-for-multicore-processors/</link> <comments>http://blog.slaunchaman.com/2011/03/03/ios-programming-for-multicore-processors/#comments</comments> <pubDate>Fri, 04 Mar 2011 02:54:31 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[Mac Programming]]></category> <category><![CDATA[Programming Tips]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Cocoa Touch]]></category> <category><![CDATA[Grand Central Dispatch]]></category> <category><![CDATA[iOS]]></category> <category><![CDATA[iPad]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[multithreading]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[performance]]></category> <category><![CDATA[programming]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=417</guid> <description><![CDATA[With the impending release of the iPad 2, understanding how to program multithreaded applications will quickly become paramount as applications continue to push the envelope to make immersive experiences with high-performance computation. Now, without actually having a multicore iPad in my hands, I can’t say exactly how the system will behave, but there are a [...]]]></description> <content:encoded><![CDATA[<p>With the impending release of <a
href="http://www.apple.com/ipad/">the iPad 2</a>, understanding how to program multithreaded applications will quickly become paramount as applications continue to push the envelope to make immersive experiences with high-performance computation. Now, without actually <em>having</em> a multicore iPad in my hands, I can’t say exactly how the system will behave, but there are a few best practices we should all be aware of when writing iOS code:</p><ul><li><strong>Using <a
href="http://developer.apple.com/library/mac/#referencelibrary/GettingStarted/GettingStartedWithCoreData/">Core Data</a>?</strong> You can’t share access to an <a
href="http://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/"><code>NSManagedObjectContext</code></a> across multiple threads, <a
href="http://developer.apple.com/library/mac/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html">dispatch queues</a>, or <a
href="http://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperationQueue_class/"><code>NSOperation</code> queues</a>, so for each one you’ll need to create a new instance. Similarly, don’t pass an <a
href="http://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/"><code>NSManagedObject</code></a> or subclass thereof between threads. Give each of your objects a unique ID—<a
href="http://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFUUIDRef/Reference/reference.html"><code>CFUUID</code></a> works well for this—and pass the ID around, pulling a new object out of your <code>NSManagedObjectContext</code> for each thread. It’s a pain, but that’s how to (safely) get around threading and Core Data.</li><li><strong><em>Always</em> call UIKit updates from the main thread.</strong> Whatever you’re doing to your user interface, be it updating a label, loading an image into an image view, <em>anything</em> that’ll be rendered to screen—and some things that won’t—should be run on the main thread. There are two main ways to do this:<ol><li><em>Use Grand Central Dispatch.</em> Using <a
href="http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/dispatch_get_main_queue.3.html"><code>dispatch_get_main_queue()</code></a>, you can get a reference to the main queue and submit blocks to it for updating your UI. This is typically a clean, easy way to refactor existing code for thread-aware programming.</li><li><em>Use <a
href="http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/performSelectorOnMainThread:withObject:waitUntilDone:"><code>-performSelectorOnMainThread:withObject:waitUntilDone:</code></a> and friends.</em> This has the drawback of only working for methods that take one or zero Objective-C objects as arguments, but can be a quick and easy way to use fire-and-forget methods like <a
href="http://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/reloadData"><code>-reloadData</code></a> on <a
href="http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableView_Class/Reference/Reference.html"><code>UITableView</code></a>.</li></ol></li><li><strong>Think about how you declare your properties.</strong> How many people have been using atomic properties? Before now, not many. In fact, before now, it was typically useless, as the chances of something interrupting your accessor methods was pretty low. Now, though, if you’re planning on accessing an object from multiple threads, you <em>really</em> need to control access to your properties.</li><li><strong>Use locks.</strong> Locks, long the scourge of the multithreaded-code author, are simply essential for some parts of multithreaded programming. Whether you’re using <a
href="http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSLock_Class/Reference/Reference.html"><code>NSLock</code></a> or a lower-level lock, or even something like Grand Central Dispatch’s counting semaphore type, <a
href="http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/doc/uid/TP40008079-CH2-SW37"><code>dispatch_semaphore_t</code></a>, protect critical regions of your code from multiple accessors with (carefully-thought-out) locked access.</li></ul><p>This list is by no means exhaustive, and Apple can do a lot to make this irrelevant (such as make UIKit threadsafe, which would be a <em>killer</em> iOS 5.0 feature), but with the iPad 2’s arrival, developers can no longer assume safety from threading problems. Be sure also to read Apple’s <a
href="http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/">Threading Programming Guide</a> to get anything I’ve left out.</p><p>It also makes a great excuse to buy an iPad 2. I mean, you need to <em>test</em> this, right?</p> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/03/03/ios-programming-for-multicore-processors/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Cocoa Touch Tutorial: Using Grand Central Dispatch for Asynchronous Table View Cells</title><link>http://blog.slaunchaman.com/2011/02/28/cocoa-touch-tutorial-using-grand-central-dispatch-for-asynchronous-table-view-cells/</link> <comments>http://blog.slaunchaman.com/2011/02/28/cocoa-touch-tutorial-using-grand-central-dispatch-for-asynchronous-table-view-cells/#comments</comments> <pubDate>Tue, 01 Mar 2011 02:23:25 +0000</pubDate> <dc:creator>Jeff Kelley</dc:creator> <category><![CDATA[Mac Programming]]></category> <category><![CDATA[Programming Tips]]></category> <category><![CDATA[Apple]]></category> <category><![CDATA[Blocks]]></category> <category><![CDATA[C]]></category> <category><![CDATA[Cocoa Touch]]></category> <category><![CDATA[Grand Central Dispatch]]></category> <category><![CDATA[iOS]]></category> <category><![CDATA[iPhone]]></category> <category><![CDATA[Mac OS X]]></category> <category><![CDATA[Objective-C]]></category> <category><![CDATA[performance]]></category> <category><![CDATA[tutorials]]></category> <category><![CDATA[UITableView]]></category> <category><![CDATA[UITableViewCell]]></category> <guid
isPermaLink="false">http://blog.slaunchaman.com/?p=403</guid> <description><![CDATA[One of the problems that an iOS developer will often face is the performance of table view cells. Table view cells are loaded on-demand by the UITableView that they’re a part of; the system calls &#8209cellForRowAtIndexPath: on the table view’s dataSource property to fetch a new cell in order to display it. Since this method [...]]]></description> <content:encoded><![CDATA[<p>One of the problems that an iOS developer will often face is the performance of table view cells. Table view cells are loaded on-demand by the <code>UITableView</code> that they’re a part of; the system calls <code>&#8209cellForRowAtIndexPath:</code> on the table view’s <code>dataSource</code> property to fetch a new cell in order to display it. Since this method is called (several times) while scrolling a table view, it needs to be very performant. You don’t have very much time to provide the system with a table view cell; take too long, and the application will appear to stutter to your users. This kills the immersion of your application and is an instant sign to users that the application is poorly-written. I guess what I’m saying is that this code needs to be <em>fast</em>. But what if something you need to do to display the table view cell takes a long time—say, loading an image?</p><p>In <a
href="http://blog.slaunchaman.com/2011/02/19/mobidevday-presentation-slides/">my MobiDevDay presentation</a> a couple of weeks ago, I illustrated a solution to this problem: Grand Central Dispatch. GCD, Apple’s new multiprocessing API in Mac OS X Snow Leopard and iOS 4, is the perfect solution for this problem. Let’s take a look at how it works.</p><p>Grand Central Dispatch operates using queues. Queues are a C typedef: <code>dispatch_queue_t</code>. To get a new global queue, we call <code>dispatch_get_global_queue()</code>, which takes two arguments: a <code>long</code> for priority and an <code>unsigned long</code> for options, which is unused, so we’ll pass <code>0ul</code>. Here’s how we get a high-priority queue:</p><pre class="brush: objc; gutter: false; title: ; notranslate">dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);</pre><p>It’s pretty straightforward. To use this queue, we add blocks of code onto it. Typically this is done with blocks (Apple’s new code encapsulation extension to the C language), though it can be done with C functions. To submit a block onto a queue for execution, use the functions <code>dispatch_sync</code> and <code>dispatch_async</code>. They both take a queue and a block as parameters. <code>dispatch_async</code> returns immediately, running the block asynchronously, while <code>dispatch_sync</code> blocks execution until the provided block returns (though you cannot use its return value). Here’s how we schedule some code onto a queue (we’ll assume this code runs after our previous example, so <code>queue</code> is already defined):</p><pre class="brush: objc; gutter: false; title: ; notranslate">dispatch_async(queue, ^{
    NSLog(@&quot;Hello, World!&quot;);
});</pre><p>It’s very easy to forget the <code>);</code> at the end of that line, so be careful.</p><p>How does this apply to table view cells? Let’s take a look at a typical scenario for loading images from disk:</p><pre class="brush: objc; first-line: 33; title: ; notranslate">- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @&quot;ExampleCell&quot;;
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:CellIdentifier] autorelease];
    }
    // Get the filename to load.
    NSString *imageFilename = [imageArray objectAtIndex:[indexPath row]];
    NSString *imagePath = [imageFolder stringByAppendingPathComponent:imageFilename];
    [[cell textLabel] setText:imageFilename];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    [[cell imageView] setImage:image];
    return cell;
}</pre><p>The problem with that code is that creating <code>image</code> blocks until <code>&#8209imageWithContentsOfFile:</code> returns. If the images are especially large, this is catastrophic. Modifying this code to use Grand Central Dispatch is simple:</p><pre class="brush: objc; first-line: 33; title: ; notranslate">- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @&quot;Cell&quot;;
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:CellIdentifier] autorelease];
    }
    // Get the filename to load.
    NSString *imageFilename = [imageArray objectAtIndex:[indexPath row]];
    NSString *imagePath = [imageFolder stringByAppendingPathComponent:imageFilename];
    [[cell textLabel] setText:imageFilename];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
    dispatch_async(queue, ^{
        UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
        dispatch_sync(dispatch_get_main_queue(), ^{
            [[cell imageView] setImage:image];
            [cell setNeedsLayout];
        });
    });
    return cell;
}</pre><p>First, we create our image asynchronously by using <code>dispatch_async()</code>. Once we have it, however, we have to come back to the main thread in order to update our table view cell’s UI (all UI updates should be on the main thread, unless you like reading crash reports). GCD has a function to get the main queue—analogous to the main thread—called <code>dispatch_get_main_queue()</code>. We can dispatch a block to <em>that</em> thread to update the UI.</p><p>By making this simple modification, we can very easily improve the performance of our table view. There are a few steps remaining, however, and this method has one serious shortcoming: if the cell is re-used by the time the image loads, it can load the wrong image into the cell. To get around this, it would be better to cache the images in an array or a dictionary (just be sure to release it in your view controller’s <code>&#8209didReceiveMemoryWarning:</code> method). That said, this is an example of something you can do quite easily to improve the performance of your application. The better it performs, the more your users will like it, and that’s the ultimate goal.</p><p>The code used in this post is available as a <a
href="https://github.com/SlaunchaMan/GCDExample">GitHub</a> repository.</p> ]]></content:encoded> <wfw:commentRss>http://blog.slaunchaman.com/2011/02/28/cocoa-touch-tutorial-using-grand-central-dispatch-for-asynchronous-table-view-cells/feed/</wfw:commentRss> <slash:comments>23</slash:comments> </item> </channel> </rss>
<!-- Dynamic page generated in 1.497 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-01-27 19:22:36 -->
<!-- Compression = gzip -->
