<?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/"
	xmlns:go='http://ns.gigaom.com/'
xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>GigaOM &#187; Apple</title>
	<atom:link href="http://gigaom.com/apple/tag/iphone-dev-sessions/feed/" rel="self" type="application/rss+xml" />
	<link>http://gigaom.com</link>
	<description></description>
	<lastBuildDate>Sun, 27 May 2012 13:01:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='gigaom.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://0.gravatar.com/blavatar/0db8f6557d022075dbbf010c54d46d93?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>GigaOM &#187; Apple</title>
		<link>http://gigaom.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://gigaom.com/osd.xml" title="GigaOM" />
	<atom:link rel='hub' href='http://gigaom.com/?pushpress=hub'/>
		<item>
		<title>iPhone Dev Sessions: Finding Your Way With MapKit</title>
		<link>http://gigaom.com/apple/iphone-dev-sessions-finding-your-way-with-mapkit/</link>
		<comments>http://gigaom.com/apple/iphone-dev-sessions-finding-your-way-with-mapkit/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 17:57:56 +0000</pubDate>
		<dc:creator>Geoffrey Goetz</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[iphone dev sessions]]></category>
		<category><![CDATA[MapKit]]></category>

		<guid isPermaLink="false">http://theappleblog.com/?p=45555</guid>
		<description><![CDATA[Looking for directions on how to create a simple map within an application can be challenging. Sometimes the simplest of typos or a missed step in the process can become very frustrating.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=174218&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Looking for directions on how to create a simple map within an application can be challenging. Sometimes the simplest of typos or a missed step in the process can become very frustrating. Many of the examples start with a finished solution and attempt to explain the code after it was written. This walkthrough, from the first step, will attempt to dissect each challenge one by one in an effort to allow the reader to pick and choose which antidotes are applicable to their particular situation.</p>
<h2><strong>Creating an Application with a Map</strong></h2>
<p>For starters, create a new View-based Application and open the default .xib file that is created. All that is really needed to get the point across is a view controller. This example will utilize a .xib file and Interface Builder, but the interactions with Interface Builder are limited to establishing a reference and a delegate. If you prefer to do the example entirely in code, that should be just fine too. From within Interface Builder, drag and drop a Map View component from the Library Window onto the View. You may want it to be just this easy, but there are a few things that we need to do before exiting Interface Builder. Take a look at the Attributes of the Map View you just added in the Inspector Window:</p>
<p><img  title="mapview" src="http://gigapple.files.wordpress.com/2010/05/mapview.png?w=272&h=112" alt="" width="272" height="112" class=" alignleft" /></p>
<p>The options are pretty straight forward to configure. Quit Interface Builder, but be sure to save all work before exiting. If you try to build and run the project at this point, it will fail. This is because the MapKit Framework has not jet been added to the project. From within Xcode, select the Frameworks folder and Add an Existing Framework to the Project. Now the project should build and execute properly. In the simulator, all that should display is a map of the world (assuming you have network connectivity on the Mac you are using to develop with).</p>
<p><img  title="addframework" src="http://gigapple.files.wordpress.com/2010/05/addframework.png?w=523&h=338" alt="" width="523" height="338" class=" alignleft" /></p>
<h2><strong>Centering the Map</strong></h2>
<p>As a first step, let&#8217;s try and take control of the World by centering the Map on just the United States. As a first step in this process, one needs to know the actual latitude and longitude of the center of the United States. Breaking away from Google (who has defined the center of the U.S. elsewhere), we will use a small park near the town of Lebanon, Kansas since they have a historical monument declaring itself as the <a href="http://en.wikipedia.org/wiki/Geographic_center_of_the_contiguous_United_States">center of the country</a>, rather than a spot just north of a country club in Coffeyville, Kansas. When working with a Map View, it wants to center on a region, more specifically a MKCoordinateRegion. Now this region in turn wants to know a location (or CLLocationCoordinate2D) and a span (or MKCoordinateSpan). Basically a region is initially configured with a center point and knowledge in coordinate terms as to how far to zoom in/out on the map. How far to zoom would define the span. The first step is ensuring that both that the MapKit and the CoreLocation frameworks have been added to the view controller’s header:</p>
<p><pre class="brush: objc;">
#import &lt;MapKit/MapKit.h&gt;
#import &lt;CoreLocation/CoreLocation.h&gt;
</pre></p>
<p>At this point it is time to establish the center of the United States by creating a location with the appropriate latitude and longitude.</p>
<p><pre class="brush: objc;">
	CLLocationCoordinate2D location;
	location.latitude = 37.250556;
	location.longitude = -96.358333;
</pre></p>
<p>Now for the tricky part. The span object will need to know about the four corners of the area in question, not just the center. The furthest points north, south, east and west. Once these coordinates are known, it is a simple calculation to determine the span. Rather than using an exact number, pad the span by 4 percent in order to make a more natural looking map:</p>
<p><pre class="brush: objc;">
	MKCoordinateSpan span;
	span.latitudeDelta = 1.04*(126.766667 - 66.95) ;
	span.longitudeDelta = 1.04*(49.384472 - 24.520833) ;
</pre></p>
<p>The center location is known and set, and the span is known and set. These are the requirements of the region:</p>
<p><pre class="brush: objc;">
	MKCoordinateRegion region;
	region.span = span;
	region.center = location;
</pre></p>
<p>Then in Interface Builder, select the Map View Component, and from the Connections Tab inside the Inspector, create a New Referencing Outlet and assign it to the File’s Owner (which in this case is the View Controller). Quit and Save Interface Builder and run the application. In the header file, be sure to create an IBOutlet for the MapView, otherwise you will not have anything to wire up when using Interface Builder.</p>
<p><pre class="brush: objc;">
	IBOutlet MKMapView *myMapView;
</pre></p>
<p>All that is left to do is to wire up the MapView that was created in Interface Builder with the View Controller, and set the region of the map View.</p>
<p><pre class="brush: objc;">
	[myMapView setRegion:region animated:NO];
	[myMapView regionThatFits:region];
</pre></p>
<p>The continental United States should now be centered within the simulator. This technique can be used at any time to center the map within any region. All that is needed is the max and min latitude, the max and min longitude, and the center lat/lng coordinates. There are other means to control the span based on just knowing the center location. What I have found is that knowing the center is not always as easy as it sounds, especially when dealing with a list of locations. It is far easier to keep track of the furthest point north, south, east and west in an effort to determine the couners of the area in question.</p>
<h2>Annotating a Map</h2>
<p>Annotating a map is basically just adding pins to it. This can occur programmatically by accessing data that has been stored locally or is accessed via a remote API, or can be the result of getting location information from either the device in the form or Core Locations API or by data entered by the user like an address. In the end, in order to get it to show up on a map (however the data is collected, stored or referenced), it must conform to the MKAnnotation protocol. The only required property of an object that adopts this protocol is a CLLocationCoordinate2D of the name coordinate:</p>
<p><pre class="brush: objc;">
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate
</pre></p>
<p>There are also two optional instance methods that can be implemented. These are not required to be added to a map, but are necessary if one wants to support callouts on the pins that display on the map. These two methods return strings and are named title and subtitle:</p>
<p><pre class="brush: objc;">
- (NSString *)title
- (NSString *)subtitle
</pre></p>
<p>Keep in mind that since you are not subclassing, any object can adopt this protocol and be added to a map as an annotation. In its simplest form, an implementation of an annotation would have at least the following declared in its header:</p>
<p><pre class="brush: objc;">
#import &lt;Foundation/Foundation.h&gt;
#import &lt;MapKit/MapKit.h&gt;
@interface AdoptingAnAnnotation : NSObject  {
}
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
- (NSString *) title;
- (NSString *) subtitle;
@end
</pre></p>
<p>What is great about the MKAnnotation protocol is that any class can adopt it. This means that if you already have a model object that has address information contained within it, you could adopt the MKAnnotation protocol in the existing class and delegate access to information already contained within that class to the optional title and subtitle accessor methods. Keeping the example simple, the following is the basics that are required to support the MKAnnotation protocol in a simple to reuse implementation:</p>
<p><pre class="brush: objc;">
#import &quot;AdoptingAnAnnotation.h&quot;
@implementation AdoptingAnAnnotation
@synthesize latitude;
@synthesize longitude;
- (id) initWithLatitude:(CLLocationDegrees) lat longitude:(CLLocationDegrees) lng {
	latitude = lat;
	longitude = lng;
	return self;
}
- (CLLocationCoordinate2D) coordinate {
	CLLocationCoordinate2D coord = {self.latitude, self.longitude};
	return coord;
}
- (NSString *) title {
        return @&quot;217 2nd St&quot;;
}
- (NSString *) subtitle {
        return @&quot;San Francisco CA 94105&quot;;
}
@end
</pre></p>
<p>Thats it! Depending on how you want to have annotations added to the map, this could be behind the scenes by parsing through the result of a network call that returns data that must be parsed through, or by using CoreLocations and adding a button to the user interface to add annotations each time the button is clicked. Using the simple implementation of a class that adopted the MKAnnotaiton protocol above, the following code would could be added anywhere within the ViewController:</p>
<p><pre class="brush: objc;">
	AdoptingAnAnnotation *someAnnotation = [[[AdoptingAnAnnotation alloc] initWithLatitude:37.786521 longitude:-122.397850 ] autorelease];
	[mMapView addAnnotation:someAnnotation];
</pre></p>
<h2>Custom Pins</h2>
<p>Default red pins are fine, but you may want to use custom annotations as well. The simplest form of customizing the annotations is to simply change the color of the pin. So we get to the main event, a means to display the annotated class on the map that we have added to the view. The first step is to decide which class will be the delegate to the MKMapView that was added to the View. Typically this is the ViewController that the MapView was added to. This can be done in Interface Builder by making the ViewController the delegate to the MapView, or in code by setting the delegate of the MapView to self in one of the init methods of the View Controller. Once this is complete, it is assumed that the View Controller has adopted the MKMapViewDelegate protocol. Once the header of the View Controller has been updated to indicate this fact, all that is required is that the following method is implemented in the View Controller class:</p>
<p><pre class="brush: objc;">
- (MKAnnotationView *) mapView:(MKMapView *) mapView viewForAnnotation:(id ) annotation {
	MKPinAnnotationView *customPinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
	customPinView.pinColor = MKPinAnnotationColorPurple;
	customPinView.animatesDrop = YES;
	customPinView.canShowCallout = YES;
	return customPinView;
}
</pre></p>
<p>In this way, one has control over some of the basic aspects of the pin annotations that are added to the mapView. If you find that the above code does not work for you, check and double-check that the delegate for the map view has been set up properly. This can be done in Interface Builder or in code as follows:</p>
<p><pre class="brush: objc;">
	[myMapView setDelegate:self];
</pre></p>
<h2><strong>Custom Annotations</strong></h2>
<p>Taking control of the Pins by implementing the mapView method in the MKMapViewDelegate protocol is a good start, but most want to abandon pins all together and utilize custom images on the MapView instead. The technique is identical, but the difference is in the implementation:</p>
<p><pre class="brush: objc;">
- (MKAnnotationView *) mapView:(MKMapView *) mapView viewForAnnotation:(id ) annotation {
	MKAnnotationView *customAnnotationView=[[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
	UIImage *pinImage = [UIImage imageNamed:@&quot;ReplacementPinImage.png&quot;];
	[customAnnotationView setImage:pinImage];
    customAnnotationView.canShowCallout = YES;
    return customAnnotationView;
}
</pre></p>
<p>The difference is that in this situation a MKAnnotationView is used instead of the MKPinAnnotation class. Try as you might, adding images to pins will not work. Setting a MKAnnotations’s image property will achieve the desired results. This is where several online code examples can be misleading by using the same reference name like pinView or annoView and only change the Class in the alloc statement. And since this is all in the MapKit framework, the imports do not need to change. Therefore this one subtle difference is often the culprit of several hours of pain and suffering.</p>
<p><em>NOTE: It is recommended that one resize the image prior to compilation using a tool like preview rather than attempt to resize the image in code.</em></p>
<h2>Annotation Callouts</h2>
<p>As we saw earlier, annotations can have titles and subtitles. These are optionally displayed when the user taps on a given pin or custom annotation. In the prior code examples, we set the property of ShowCallout to YES. These callouts can also have images associated with them. These images are not meant to be the same image that was utilized as the pin image as these will be displayed in the callout above the pin when the pin receives a tap event. This technique will expand upon the one utilized in either of the two prior examples by adding the following two lines of code inside of the MKAnnotationView delegate method:</p>
<p><pre class="brush: objc;">
	UIImageView *leftIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@&quot;LeftIconImage.png&quot;]];
	customAnnotationView.leftCalloutAccessoryView = leftIconView;
</pre></p>
<p>You&#8217;re not required to use the MKAnnotationView in order to add an image to the left callout accessory view. This can also be done with the MKPinAnnotationView.</p>
<p><em>NOTE: It is recommended that you resize the image prior to compilation using a tool like Preview rather than attempt to resize the image in code.</em></p>
<p><img  title="Simulator Result" src="http://gigapple.files.wordpress.com/2010/05/simulatorresult.png?w=401&h=738" alt="Simulator Result" width="401" height="738" class=" alignleft" /></p>
<h2>Assigning Actions to Annotation Callouts</h2>
<p>Finally there is the matter of assigning an action to an annotation’s callout. Typically, these actions pop another view onto the stack, but really can do anything. What is required here is that a button be added to the AnnotationView (either the MKPinAnnotiaonView or the MKAnnotationView example above). This button will assign one of its control events to a method typically in the same ViewController that is also the delegate to the MapView itself:</p>
<p><pre class="brush: objc;">
	UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
	[rightButton addTarget:self action:@selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];
	customAnnotationView.rightCalloutAccessoryView = rightButton;
</pre></p>
<p>Just as in the prior example, this code should be added to the delegate method implemented in the View controller. For example, if all of the details were added to the MKAnnotationView, the code would look as follows:</p>
<p><pre class="brush: objc;">
- (MKAnnotationView *) mapView:(MKMapView *) mapView viewForAnnotation:(id ) annotation {
	MKAnnotationView *customAnnotationView=[[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil] autorelease];
	UIImage *pinImage = [UIImage imageNamed:@&quot;ReplacementPinImage.png&quot;];
	[customAnnotationView setImage:pinImage];
    customAnnotationView.canShowCallout = YES;
	UIImageView *leftIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@&quot;LeftIconImage.png&quot;]];
	customAnnotationView.leftCalloutAccessoryView = leftIconView;
	UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
	[rightButton addTarget:self action:@selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];
	customAnnotationView.rightCalloutAccessoryView = rightButton;
    return customAnnotationView;
}
- (IBAction) annotationViewClick:(id) sender {
    NSLog(@&quot;clicked&quot;);
}
</pre></p>
<h2>Conclusion</h2>
<p>These are the basic building blocks that are used when working with maps on the iPhone. These building blocks can be used in isolation, or can be added together to work with each other in concert. For instance, when adding an annotation to a map, the map can be re-centered taking the location new annotation into account. While these bare bones examples are not a true representation of a real world application, they were meant to illustrate the basics in a very minimalist approach that simply works.</p>
<h2>References</h2>
<ul>
<li><a href="http://developer.apple.com/iphone/library/documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html">iPhone OS Reference Library - MKMapView Class Reference</a></li>
<li><a href="http://developer.apple.com/iphone/library/documentation/MapKit/Reference/MKAnnotation_Protocol/Reference/Reference.html">iPhone OS Reference Library - MKAnnotation Protocol Reference</a></li>
<li><a href="http://developer.apple.com/iphone/library/documentation/MapKit/Reference/MKMapViewDelegate_Protocol/MKMapViewDelegate/MKMapViewDelegate.html">iPhone OS Reference Library - MKMapViewDelegate Protocol Reference</a></li>
<li><a href="http://developer.apple.com/iphone/library/documentation/MapKit/Reference/MKAnnotationView_Class/Reference/Reference.html">iPhone OS Reference Library - MKAnnotationView Class Reference</a></li>
</ul>
<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=174218&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/iphone-dev-sessions-finding-your-way-with-mapkit/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	 <go:thumbnail>http://gigapple.files.wordpress.com/2010/05/mapkit_thumb.png?w=130</go:thumbnail> 
		<media:thumbnail url="http://gigapple.files.wordpress.com/2010/05/mapkit_thumb.png?w=210" />
		<media:content url="http://gigapple.files.wordpress.com/2010/05/mapkit_thumb.png?w=210" medium="image">
			<media:title type="html">mapkit_thumb</media:title>
		</media:content>

		<media:content url="http://1.gravatar.com/avatar/940906757c2b8631cab8b60f4adb61a3?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">ggeoffre</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/05/mapview.png" medium="image">
			<media:title type="html">mapview</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/05/addframework.png" medium="image">
			<media:title type="html">addframework</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/05/simulatorresult.png" medium="image">
			<media:title type="html">Simulator Result</media:title>
		</media:content>
	</item>
		<item>
		<title>iPhone Dev Sessions: Responsive Web-Enabled iPhone Apps</title>
		<link>http://gigaom.com/apple/iphone-dev-sessions-responsive-web-enabled-iphone-apps/</link>
		<comments>http://gigaom.com/apple/iphone-dev-sessions-responsive-web-enabled-iphone-apps/#comments</comments>
		<pubDate>Fri, 28 May 2010 12:00:08 +0000</pubDate>
		<dc:creator>Andy Boothe</dc:creator>
				<category><![CDATA[How-To]]></category>
		<category><![CDATA[iPhone, iPod, iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iphone dev sessions]]></category>

		<guid isPermaLink="false">http://theappleblog.com/?p=45024</guid>
		<description><![CDATA[A good iPhone app has to be simple, intuitive, responsive, and give users a compelling reason to use it. Unfortunately, there’s no recipe for how to write a simple, intuitive and compelling app. Writing a responsive app, however, is much easier.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=174197&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Back in August 2009, <a href="http://www.shufflegazine.com/">Shufflegazine</a> featured an article talking about <a href="http://www.shufflegazine.com/2009/08/08/my-apple-what-makes-a-good-iphone-app/">what makes a good iPhone app</a>. The article has a good discussion about what apps are popular and why, and ultimately concludes that a good app has to be simple, intuitive, responsive, and give users a compelling reason to use it.</p>
<p>Unfortunately, there’s no recipe for how to write a simple, intuitive and compelling app. Our best bet for getting our hands on that recipe is probably <a href="http://www.facebook.com/pages/The-Most-Interesting-Man-In-The-World/90261849840">this guy</a>, but until he makes that announcement, handling these points is left as an exercise for the reader.</p>
<p>Writing a <em>responsive </em>app, however, is <em>much</em> easier.</p>
<p>A good working definition for a “responsive” app is one that responds to user input quickly and doesn’t hang without telling the user what’s going on. The rule of thumb here is that <a href="http://www.useit.com/papers/responsetime.html">GUIs should respond to input in no more than 1 second</a>, so the bar is set pretty high, especially for web-enabled apps. This article describes the most common reason GUIs get unresponsive and what to do about it.</p>
<h2>How Do These Newfangled GUIs Work, Again?</h2>
<p>Cocoa Touch’s GUI (like most GUIs) is built on an “event + event loop” architecture. User interactions like taps and keypresses are translated to <a href="http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSEvent_Class/Reference/Reference.html">events</a>, and these events are then processed one-by-one in the imaginatively named <a href="http://developer.apple.com/Mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSRunLoop_Class/Reference/Reference.html">event loop</a>:</p>
<div id="attachment_45281" class="wp-caption aligncenter" style="width: 580px"><img  title="gui-event-workflow" src="http://gigapple.files.wordpress.com/2010/05/gui-event-workflow1.png?w=570&h=389" alt="GUI Event Workflow" width="570" height="389" class=" alignleft" /><p class="wp-caption-text">Simplified Event Flow in a Cocoa App</p></div>
<p>As long as each event gets processed quickly, the GUI stays nice and zippy. But because events are processed serially, one event can back up the whole gravy train. If one event takes five second to process, then the GUI will be completely unresponsive for those five seconds until the event loop can start processing new events again.</p>
<p>But what if you have some GUI resources that take five seconds to load? We can’t load them all at app initialization time because we don’t always know what resources we’ll need when the app is starting up, especially for things like profile pictures. Also, the iPhone is an embedded platform, so memory for preloading is in short supply, anyway. How, then, can we appease the event loop tiki gods? The answer, young grasshopper, is to load such resources asynchronously, and then update the GUI when they’re done loading.</p>
<h2>Responsiveness Test Bench</h2>
<p>To illustrate these ideas, I’ve made a simple iPhone app that loads an image resource for display in an iPhone app GUI three different ways.</p>
<div id="attachment_46194" class="wp-caption aligncenter" style="width: 424px"><img  title="responsiveness-testbench2" src="http://gigapple.files.wordpress.com/2010/05/responsiveness-testbench2.png?w=414&h=770" alt="" width="414" height="770" class=" alignleft" /><p class="wp-caption-text">The Responsiveness Tester. The people responsible for the appearance of this iPhone app have been sacked.</p></div>
<p>Each method loads and displays the same image, but does the loading differently to demonstrate the effect each approach has on GUI responsiveness. The source code for this app is attached to this article if you’d like to play along at home.</p>
<p>When the user chooses a loading technique by tapping its table row, a corresponding method is called to illustrate that loading technique. These methods are called directly from the <code>UITableViewDelegate</code> <code>tableView:didSelectRowAtIndexPath:</code> method, which runs in the event loop, so all this code runs directly in the GUI thread.</p>
<p>First, let’s have a look at the code from the load-from-file example:</p>
<p><pre class="brush: objc;">
- (void)showSynchFileDemoWithTitle:(NSString *)title {
    UIImage *image;
    image = [UIImage imageNamed:@&quot;apple-logo.png&quot;];
    EagerViewController *view=[[EagerViewController alloc]
        initWithNibName:@&quot;EagerViewController&quot; bundle:nil title:title image:image];
    [self.navigationController pushViewController:view animated:YES];
    [view release];
}
</pre></p>
<p>The code looks like it sounds, right? We load the image from disk, use it to create a new <code>UIViewController</code>, push that <code>UIViewController</code> onto our <code>UINavigationController</code>, and then release the <code>UIViewController</code> back into the wild. This is exactly why synchronous loading is so popular: it’s <em>ridiculously simple.</em> And since we’re just loading a small image from a file, the GUI is still zippy, so synchronous loading is actually fine here.</p>
<p>Now let’s look at loading that same image from a synchronous web request instead of a file:</p>
<p><pre class="brush: objc;">
- (void)showSynchWebDemoWithTitle:(NSString *)title {
    UIImage *image;

    NSURLRequest  *request=[NSURLRequest requestWithURL:[NSURL
        URLWithString:IMAGEURL]];
    NSURLResponse *response=nil;
    NSError *error=nil;
    NSData *content=[NSURLConnection sendSynchronousRequest:request
        returningResponse:&amp;response error:&amp;error];
    if(content == nil)
        image = [UIImage imageNamed:@&quot;big-red-x.png&quot;];
    else
        image = [UIImage imageWithData:content];

    EagerViewController *view=[[EagerViewController alloc]
        initWithNibName:@&quot;EagerViewController&quot; bundle:nil title:title image:image];
    [self.navigationController pushViewController:view animated:YES];
    [view release];
}
</pre></p>
<p>The code is slightly more complicated, but still not too bad. We set up a web request for the image, wait for it to download, build an image with the contents of that request if it succeeded or load a default image if it failed, and then build our <code>UIViewController</code> from that image. Still nice and easy, but how does it perform?</p>
<div id="attachment_46195" class="wp-caption aligncenter" style="width: 620px"><img  title="unresponsive-app2" src="http://gigapple.files.wordpress.com/2010/05/unresponsive-app2.png?w=610&h=292" alt="" width="610" height="292" class=" alignleft" /><p class="wp-caption-text">The problem with synchronous web loading. Hang much?</p></div>
<p>Turns out, not so well. After the user taps “Synchronous from Web,” the app just kind of sits there for a few seconds before it shows the next view. Why? The synchronous web request loading the image in the event loop takes a while to complete, which blocks the event loop and hangs the GUI. This kind of code is surprisingly common despite the hangs it causes. Unless you’re willing to tick off your customers, which is <em>usually</em> considered harmful, synchronous web loading in the event loop is right out.</p>
<p>So what’s the asynchronous web loading equivalent look like? Behold, ye mortals, and<em> </em>despair&#8230;</p>
<p>From RootViewController.m:</p>
<p><pre class="brush: objc;">
- (void)showAsynchWebDemoWithTitle:(NSString *)title {
    LazyViewController *view=[[LazyViewController alloc]
        initWithNibNamed:@&quot;LazyViewController&quot; bundle:nil title:title
        imageURL:[NSURL URLWithString:IMAGEURL]];
    [self.navigationController pushViewController:view animated:YES];
    [view release];
}
</pre></p>
<p>From LazyViewController.m:</p>
<p><pre class="brush: objc;">
- (id)initWithNibNamed:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil title:(NSString *)title imageURL:(NSURL *)imageURL {
    if(self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        self.navigationItem.title = title;
        if(imageURL != nil) {
            self.getlogo = [AtomicAsynchronousWebRequest requestWithURL:imageURL
                andDelegate:self];
        }
    }
    return self;
}

- (void)updateLogoWithImage:(UIImage *)image {
    [self.logo stopLoadingWithActiveView:[[[UIImageView alloc] initWithImage:image]
        autorelease]];
}

- (void) atomicAsynchronousWebRequest:(AtomicAsynchronousWebRequest *)request didFailWithError:(NSError *)error {
    if(request == self.getlogo) {
        [self updateLogoWithImage:[UIImage imageNamed:@&quot;big-red-x.png&quot;]];
        self.getlogo = nil;
    }
    else {
        // We have no idea which request this is. Just log it and move on.
        NSLog(@&quot;Failed unrecognized HTTP request: %@&quot;, request);
    }
}

- (void)atomicAsynchronousWebRequest:(AtomicAsynchronousWebRequest *)request didSucceedWithResponse:(NSURLResponse *)response andContent:(NSData *)content {
    if(request == self.getlogo) {
        [self updateLogoWithImage:[UIImage imageWithData:content]];
        self.getlogo = nil;
    }
    else {
        // We have no idea which request this is. Just log it and move on.
        NSLog(@&quot;Succeeded unrecognized HTTP request: %@&quot;, request);
    }
}
</pre></p>
<p>Oh… that’s all? Well, I guess that’s not <em>so</em> bad. We pass the URL for our image to the <code>UIViewController</code> initializer, and the <code>UIViewController</code> then starts an asynchronous web request for the image and updates the logo view with an image when the web request either succeeds or fails. (Observant readers will notice some custom methods above. Hang tight, we’ll talk about those in a minute.) What does all this trouble buy us?</p>
<div id="attachment_46196" class="wp-caption aligncenter" style="width: 620px"><img  title="responsive-app2" src="http://gigapple.files.wordpress.com/2010/05/responsive-app2.png?w=610&h=296" alt="" width="610" height="296" class=" alignleft" /><p class="wp-caption-text">Nice and Zippy. Asynchronous Loading FTW!</p></div>
<p>A wonderfully responsive app, that’s what. The transition from the first view to the second view is instantaneous; the second view shows its spinner until the web request completes or fails, and then the logo is updated with a new image. Why is this UI so snappy? Because all long-running operations are performed outside the message loop, so nothing hangs the GUI thread. Lazy loading for slow resources is clearly the way to go.</p>
<p>And if you think about it, this approach is good not only because it runs faster, but also because it’s more modular. The <code>UIViewController</code> being created knows what it’s displaying; it should probably be loading its resources too, especially if that loading is complex, in case that <code>UIViewController</code> needs to be reused elsewhere in the app.</p>
<p>So… sweet. A <em>twofer</em>.</p>
<h2>Being Lazy About Being Lazy</h2>
<p>If asynchronous loading is what we need to be doing &#8212; and it <em>is &#8211;</em> then how can we make it easy? It turns out that asynchronous loading is easier in Objective-C than it is in many other languages.</p>
<p>In Java, for example, asynchronous loading requires you to mess with callbacks and <code>Thread</code>s, <code>SwingWorker</code>s, or E<code>xecutorService</code>s, which feels like jumping through a bunch of flaming hoops while wearing a newspaper tutu. In Objective-C, though, web requests are baked into the API and already have asynchronous callback functionality, which means that asynchronous loading can be had essentially for free, especially if we do a little customization of our own.</p>
<p>The app uses two custom classes. I’ll discuss them here just in case the classes themselves or what they do is useful to other developers. Both classes are in the attached source if you want to put your eyes on them, or use them for your own <em>nefarious</em> purpose.</p>
<p><strong>AtomicAsynchronousWebRequest</strong></p>
<p>The iPhone SDK’s generalized web request API is <code>NSURLConnection</code>, and you can find a good primer on how to use it <a href="http://developer.apple.com/mac/library/documentation/cocoa/conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html">here</a>. The <code>NSURLConnection</code> exposes way more features than most apps need, though, like hooks for reacting to redirects and chunked input, which makes it more difficult to use than it needs to be. <code>AtomicAsynchronousWebRequest</code> is a thin wrapper around <code>NSURLConnection</code> that lets developers perform the most common web tasks (namely atomic GETs and POSTs) asynchronously by implementing a dead-simple 2-method protocol.</p>
<p><strong>DelayedLoadView</strong></p>
<p>While the iPhone has a nice “spinner” GUI element (<code>UIActivityIndicatorView</code>) that’s handy for telling the user something is loading, it has no explicit API for populating GUI views lazily. <code>DelayedLoadView</code> is essentially a “container” view that shows a spinner until it’s updated with its “real” content view, which makes handling activity indicators and lazy content <em>really</em> easy, especially for GUIs built-in Interface Builder.</p>
<p><strong>Gotchas</strong></p>
<p>A couple gotchas have been glossed over in the interest of keeping things at least a <em>little</em> brief. Now that we’re past the good stuff, I’ll mention a few of them here, just in case you want to get creative on your own:</p>
<ol>
<li><em>All GUI updates must happen on the GUI thread.</em> Cocoa Touch GUI elements, like GUI elements in most toolkits, are not thread-safe. So, if you need to interact with a GUI element, you need to do it from the main thread. If you’re not making your own threads, you probably don’t need to worry about this. If you are, you may need to make use of <code>NSObject</code>’s <a href="http://developer.apple.com/mac/library/documentation/cocoa/reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/performSelectorOnMainThread:withObject:waitUntilDone:"><code>performSelectorOnMainThread:withObject:waitUntilDone:</code></a> or similar.</li>
<li><em>Remember that <code>UIViewController</code> <code>IBOutlet</code>s are not initialized after <code>super</code>’s initializer completes</em>. Instead, the <code>UIViewController</code> must be set to appear before <code>IBOutlet</code>s are properly connected. This means that failure conditions can’t really be handled inside a <code>UIViewController</code> initializer, so any custom load code you write needs to take that into account. If you want an example of how to work around this issue, check how <code>AtomicAsynchronousWebRequest</code> calls its failure method from its initializer roundabouts using a <code>performSelector</code> call.</li>
<li><em><code>UIActivityIndicatorViews</code> are kind of confusing</em>. You probably want to set <code>hidesWhenStopped</code> to <code>YES</code>. That way, <code>startAnimating</code> and <code>stopAnimating</code> will do what you expect them to. If you don’t see a spinner and you expect to, make sure your <code>UIActivityIndicatorView</code> isn’t hidden. If you see a spinner but it’s not spinning, you need to call <code>startAnimating</code>.</li>
<li><em>Not all long-running operations have asynchronous callbacks baked in. </em>Web requests do, which is very handy, but if you need to do some other kind of loading you’ll have to get creative. If you’re only going to load things now and then, using <code>performSelectorInBackground:withObject:</code> is probably just fine. If you’re going to be doing a lot of loading, though, you won’t want to create a new background thread each time you load something, so you’ll probably want to create a custom <a href="http://developer.apple.com/Mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSRunLoop_Class/Reference/Reference.html"><code>NSRunLoop</code></a> and kick off your loading with <code>performSelector:onThread:withObject:waitUntilDone:</code>. You can synch up the GUI when loading’s done with a simple <code>performSelectorOnMainThread:withObject:waitUntilDone:</code>.</li>
</ol>
<h2>Conclusion</h2>
<p>You’re now an expert on how to build responsive network-enabled GUIs! Or at least you know more than you did.</p>
<p>It’s worth mentioning that even though the article focused on loading images, the very same principles can be applied to executing web service calls, loading web pages, or any other task that requires time to complete.</p>
<p>I now expect <em>all apps </em>to have responsive GUIs, even if they’re loading resources from the web. You’ve been warned. <em>I’ve got my eye on you, iPhone developers.</em></p>
<p>Stay <code>QWERTY</code>, my friends.</p>
<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=174197&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/iphone-dev-sessions-responsive-web-enabled-iphone-apps/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	 <go:thumbnail>http://gigapple.files.wordpress.com/2010/05/iphoneresponsive_thumb.jpg?w=130</go:thumbnail> 
		<media:thumbnail url="http://gigapple.files.wordpress.com/2010/05/iphoneresponsive_thumb.jpg?w=210" />
		<media:content url="http://gigapple.files.wordpress.com/2010/05/iphoneresponsive_thumb.jpg?w=210" medium="image">
			<media:title type="html">iphoneresponsive_thumb</media:title>
		</media:content>

		<media:content url="http://0.gravatar.com/avatar/056ee65d9efbde501940a85c64b92ffc?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">sigpwned</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/05/gui-event-workflow1.png" medium="image">
			<media:title type="html">gui-event-workflow</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/05/responsiveness-testbench2.png" medium="image">
			<media:title type="html">responsiveness-testbench2</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/05/unresponsive-app2.png" medium="image">
			<media:title type="html">unresponsive-app2</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/05/responsive-app2.png" medium="image">
			<media:title type="html">responsive-app2</media:title>
		</media:content>
	</item>
		<item>
		<title>iPhone Dev Sessions: Using Singletons</title>
		<link>http://gigaom.com/apple/iphone-dev-sessions-using-singletons/</link>
		<comments>http://gigaom.com/apple/iphone-dev-sessions-using-singletons/#comments</comments>
		<pubDate>Tue, 18 May 2010 15:25:08 +0000</pubDate>
		<dc:creator>Geoffrey Goetz</dc:creator>
				<category><![CDATA[How-To]]></category>
		<category><![CDATA[iPhone, iPod, iPad]]></category>
		<category><![CDATA[Walkthroughs]]></category>
		<category><![CDATA[iphone dev sessions]]></category>
		<category><![CDATA[Singletons]]></category>

		<guid isPermaLink="false">https://gigapple.wordpress.com/?p=44800</guid>
		<description><![CDATA[Managing an application’s state can sometimes require complex interaction with persistence and messaging with various resources, or it can be as simple as keeping track of a counter from one view to the next.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=174182&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Managing an application’s state can sometimes require complex interaction with persistence and messaging with various resources, or it can be as simple as keeping track of a counter from one view to the next.</p>
<p>Two popular techniques to pass references to objects from one view to the next are to create properties in the Application Delegate, or to continue to pass references from one view to the next like a relay race passes a baton from one runner to the next using a series of carefully placed update methods making for an allocation nightmare and increase the opportunities for memory leaks or the hard to track down crashes. Sometimes this need in programming is referred to as implementing Global Variables. There is also a well established design pattern that can assist with this need as well, it is called the Singleton Pattern.</p>
<h2><strong>Singleton Pattern<br />
</strong></h2>
<p>The Singleton Pattern is a derivative of the Factory Pattern that ensures that one and only one instance of an Object can ever exist. By creating one or more implementations of the Singleton Pattern within a given application, the concept of ‘global variables’ can better be managed through tighter control. This allows for what is called lazy instantiation. If you do not need the variable based on what is going on in the application, then do not ask for or create an instance of one.  In Objective-C, Apple has outlined the recommended technique for implementing the singleton pattern.</p>
<div id="attachment_45007" class="wp-caption aligncenter" style="width: 310px"><img  title="Objective-C Singleton Pattern" src="http://gigapple.files.wordpress.com/2010/04/objectivec-singletonpattern.png?w=300&h=296" alt="Objective-C Singleton Pattern" width="300" height="296" class=" alignleft" /><p class="wp-caption-text">Objective-C Singleton Pattern</p></div>
<p><pre class="brush: objc;">
static MySingletonClass *sharedGizmoManager = nil;
(MySingletonClass*)sharedManager{
  if (sharedSingletonManager == nil) {
    sharedSingletonManager = [[super allocWithZone:NULL] init];
  }
  return sharedGizmoManager;
}
(id)allocWithZone:(NSZone *)zone{
  return [[self sharedManager] retain];
}
(id)copyWithZone:(NSZone *)zone{
  return self;
}
(id)retain{
  return self;
}
(NSUInteger)retainCount{
  return NSUIntegerMax;
}
(void)release{
  //do nothing
}
(id)autorelease{
  return self;
}
</pre></p>
<p>But you may find that the following is all that is necessary:</p>
<p><em><strong>Singleton.h</strong></em></p>
<p><pre class="brush: objc;">
#import &lt;Foundation/Foundation.h&gt;
@interface Singleton : NSObject {
}
+ (Singleton*) retrieveSingleton;
@end
</pre></p>
<p><em><strong>Singleton.m</strong></em></p>
<p><pre class="brush: objc;">
#import &quot;Singleton.h&quot;
@implementation Singleton
static Singleton *sharedSingleton = nil;
+ (Singleton*) retrieveSingleton {
  @synchronized(self) {
    if (sharedSingleton == nil) {
      sharedSingleton = [[Singleton alloc] init];
    }
  }
  return sharedSingleton;
}
+ (id) allocWithZone:(NSZone *) zone {
  @synchronized(self) {
    if (sharedSingleton == nil) {
      sharedSingleton = [super allocWithZone:zone];
      return sharedSingleton;
    }
  }
  return nil;
}
@end
</pre></p>
<p>Try and keep each singleton’s scope limited to manage only the information that is related to a particular use case and not as a catch-all for all global information across the application. It is probably best to utilize each singleton as a delegate to the information it is responsible for managing, and not use it as a means to gain access to any objects it has associations with. Although on the iPhone, and when being used in primarily a read only or a write seldom implementation, the risk of writing code that is not thread safe increases when utilizing shared objects. Keeping concurrency in mind, and utilizing the singleton as a delegate to the information at hand, one can watch out for multi thread related issues and deal with them in kind. One thing to watch out for would be include updating or setting properties of the singleton from within an implemented perform selector or a notification. If concurrency issues do arise, it may become necessary to synchronize access to certain properties or methods.</p>
<h2><strong>No, not the AppDelegate!</strong></h2>
<p>So why not just keep adding properties to the AppDelegate? After all, the AppDelegate is a singleton as well and is therefore accessible by invoking the sharedApplication class method. The problem with this techniques is that you end up loading up the application with too much information that may or may not be necessary depending on what functions the user chooses to evoke. It could also lead to longer and longer startup times. Get the application started as quickly as possible, and don’t leave the user hanging for too long.</p>
<h2><strong>What about Global Constants?</strong></h2>
<p>Keep in mind that this is not the best technique to employ if all you need is a means to define and gain access to Global Constants. The quickest way to do that is to create a Precompiled Prefix Header file and include that in your project. By default, most of the projects generated in XCode that create iPhone Applications will include a file with an extension of .pch. This file will initially look like the following:</p>
<p><pre class="brush: objc;">
#ifdef __OBJC__
#import &lt;Foundation/Foundation.h&gt;
#import &lt;UIKit/UIKit.h&gt;
#endif
</pre></p>
<p>One can then add any number of #define statements that will be included in all header files across the entire project.</p>
<p><pre class="brush: objc;">
#define SOME_STRING_CONSTANT @&quot;My Important String&quot;
</pre></p>
<h2><strong>Conclusion</strong></h2>
<p>The Singleton Pattern can be used to make the complex and ugly means of sharing a simple variable between two different views or view controls an easy task. If used sparingly and some basic guidelines are followed as not to bloat the application and create a multi thread nightmare to debug, this technique can be quite useful. Much more so than passing Objects back and forth among views or by breaking the encapsulation of the AppDelegate by assigning it more responsibility than it should have.</p>
<p><em>References</em></p>
<ul>
<li><a href="http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32">Mac OS X Reference Library &#8211; Cocoa Fundamentals Guide &#8211; Creating a Singleton Instance</a></li>
<li><a href="https://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html">iPhone OS Reference Library &#8211; UIApplication Class Reference</a></li>
<li><a href="http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/XcodeBuildSystem/800-Reducing_Build_Times/bs_speed_up_build.html#//apple_ref/doc/uid/TP40002695-SW1">Mac OS X Reference Library &#8211; Xcode Build system Guide &#8211; Using a Precompiled Prefix Header</a></li>
</ul>
<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=174182&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/iphone-dev-sessions-using-singletons/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/940906757c2b8631cab8b60f4adb61a3?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">ggeoffre</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/04/objectivec-singletonpattern.png?w=300" medium="image">
			<media:title type="html">Objective-C Singleton Pattern</media:title>
		</media:content>
	</item>
		<item>
		<title>iPhone Dev Sessions: Making a Splash Screen</title>
		<link>http://gigaom.com/apple/iphone-dev-sessions-making-a-splash-screen/</link>
		<comments>http://gigaom.com/apple/iphone-dev-sessions-making-a-splash-screen/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 20:00:16 +0000</pubDate>
		<dc:creator>Geoffrey Goetz</dc:creator>
				<category><![CDATA[How-To]]></category>
		<category><![CDATA[iPhone, iPod, iPad]]></category>
		<category><![CDATA[Walkthroughs]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iphone dev sessions]]></category>

		<guid isPermaLink="false">http://theappleblog.com/?p=44273</guid>
		<description><![CDATA[All too often an iPhone application’s launch sequence is an overlooked detail. The most common approach is to misuse the provided Default.png file as a splash screen. This detailing of an application is more than a little challenging if you want to get it right.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=174160&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>All too often an iPhone application’s launch sequence is an overlooked detail. The most common approach is to misuse the provided Default.png file as a splash screen. As it turns out, this detailing of an application is more than a little challenging if you want to get it right and stay within Apple’s guidelines.</p>
<p>The key to a smooth and professional looking launch sequence starts with knowing exactly where the application will land at startup. Some applications start at exactly the same place each and every successive launch, others attempt to preserve the application&#8217;s state and launch into the screen where the user last used the application. Keeping this in mind can change the strategy of how the launch sequence is implemented. This includes screen orientation as well as how and even if the status bar it to be displayed.</p>
<p>One may witness flickering of the status bar from blue, to black or from black to blue during the launch sequence. This is mainly due to the fact that there are two places to change the behavior of the status bar. One is hidden in the info.plist file, and the other is typically via code in the Application Delegate’s <code>applicationDidFinishLaunching</code> method. The <code>info.plist</code> configuration is used before the main window is loaded, and the code in the Application Delegate is used during the launching of the main window. The reason one may want to utilize both styles is to take advantage of a full screen splash page, and then enable the appropriate looking status bar once the application has finished loading.</p>
<p>For the purpose of this example application, we will assume that the user state is preserved between executions, and we do not know exactly what the screen will look like when the user enters the application. We will therefore be implementing a full-screen splash view that will have the status bar hidden during the launch sequence. Once the splash view has disappeared, a black opaque status bar will be utilized throughout the application. It is also assumed that the application will launch in portrait mode, and that the first screen the user will see will also be in portrait mode.</p>
<h2>Editing the Configuration File</h2>
<p>The first order of business is to take care of the status bar. In Xcode, locate the <code>info.plist</code> file for the project. To add an additional property to the plist file, simply select one of the entries and click on the plus tab that appears to the right and select Status Bar Style from the drop down list:</p>
<div id="attachment_44274" class="wp-caption alignnone" style="width: 580px"><img  title="Edit Projects plist File" src="http://gigapple.files.wordpress.com/2010/04/image-001.jpg?w=570&h=337" alt="Edit Projects plist File" width="570" height="337" class=" alignleft" /><p class="wp-caption-text">Edit Projects plist File</p></div>
<p>There are only three different styles to choose from. Try each style out to see which one fits the needs of the application being developed. For this example we will set the style to <code>UIStatusBarStyleDefault</code>.</p>
<p><strong>UIStatusBarStyles:</strong><br />
<code>UIStatusBarStyleDefault</code> &#8212; Gray (the default)<br />
<code>UIStatusBarStyleBlackTranslucent</code> &#8212; Transparent black (specifically, black with an alpha of 0.5)<br />
<code>UIStatusBarStyleBlackOpaque</code> &#8212; Opaque black</p>
<p>If on the other hand the desire is to hide the status bar when the application launches, then yet another property needs to be set. In this case, add the &#8220;Status Bar is initially hidden&#8221; property to the plist file and be sure to check the box next to the property.</p>
<h2>Editing the Application Delegate code</h2>
<p>So now that the status bar style is set, and initially hidden, how does one get the status bar to display again? You can actually turn the status bar on and off programmatically via code. This is particularly handy when the need arises to display a full screen view, such as the splash screen this application is utilizing. In the <code>applicationDidFinishLaunching</code> method of the Application’s designated AppDelegate class, add the following line of code to make the status bar visible again:</p>
<p><pre class="brush: objc;">
- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Override point for customization after app launch
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarHidden:NO animated:YES];
}
</pre></p>
<h2>Adding a Default.png Image</h2>
<p>Surprisingly, the size of this file is not as important as the naming convention of the file. Default.png is a case sensitive PNG file. The image should be 480&#215;320 according to Apple. Following Apple’s conventions, this image should look like the view that the user will see when the application has launched, and not the actual splash screen.</p>
<p>Xcode provides a mechanism to create a Default.png file from an attached device running the application. From the Organizer window, select the device, click on screenshots and click capture. To make that screenshot your application’s default image, click Save As Default Image. Even though the image that is created includes the status bar as it looked when the screen shot was captured, the iPhone OS replaces it with the current status bar when your application launches. Just to be clear, this is not a splash screen&#8230;not yet.</p>
<h2>Long Launch Sequences to Varying Views</h2>
<p>So far, this is what most applications will implement if they implement any sort of controlled visual experience when the application launches. If you follow Apple’s guidelines, and the image you produce is the first screen that the user will see, all is good. Except, what if the launch sequence is not as fast as the user expects? What if the application preserves state and lands on a different view based on the users last know state? Then this technique is not up to the task.</p>
<p>Photoshop a branded image representing the application and save it as a PNG image sized at 480&#215;320. Do not include a status bar of any kind in the image file being created. Add this image file to the project. Now the application sort of has a splash screen, through a misused implementation of the Default.png file. To correct this, simply add an image view as a property to the App Delegates header and create it as follows:</p>
<p><pre class="brush: objc;">
    splashView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    splashView.image = [UIImage imageNamed:@&quot;Default.png&quot;];
    [window addSubview:splashView];
    [window bringSubviewToFront:splashView];
</pre></p>
<p>At this point, the image view is utilizing the exact same image file that was created in Photoshop. There&#8217;s no chance of the initial view being different than the Default.png file at this point. The one remaining problem is the timing of when to remove the image view from the subview. This can be handled in one of two ways&#8230;</p>
<h2>Controlling the Duration of the Splash Screen</h2>
<p>The first option is for those with quick startup times that just want a splash screen. In this situation, create a method to remove and release the splash view, then calling that method via a timed perform selector call as follows:</p>
<p><pre class="brush: objc;">
    [self performSelector:@selector(removeSplash) withObject:nil afterDelay:1.5];
</pre></p>
<p>The <code>removeSplash</code> method does just that, removes the image view from the subview and releases the object.</p>
<p><pre class="brush: objc;">
    -(void)removeSplash;
    {
      [splashView removeFromSuperview];
      [splashView release];
    }
</pre></p>
<p>The second method uses the same remove splash method, but relies on the built in event management to trigger when the method gets called.</p>
<p><pre class="brush: objc;">
    [[NSNotificationCenter defaultCenter] addObserver:self
          selector:@selector(saveClaim:)
          name:@&quot;RemoveSplashScreen&quot;
          object:nil];
</pre></p>
<p>Now all that needs to be done is to post the notification from anywhere. This technique is particularly useful if the reason that the launch sequence is taking a long time has nothing to do with code that was implemented in the App Delegate.</p>
<p><pre class="brush: objc;">
    [[NSNotificationCenter defaultCenter]
          postNotificationName: @&quot;RemoveSplashScreen&quot;
          object: nil];
</pre></p>
<p>This technique can be employed from anywhere within the application. Removing the observer after the fact may avoid crashes if there is an opportunity for this notification to be fired multiple times. Releasing an object when no object it there to be released can lead to troublesome crashes to track down. The quick and dirty is to use the delay on the <code>performSelector</code> call.</p>
<h2>Conclusion</h2>
<p>And there it is, a splash screen that conforms to Apple’s guidelines. No hidden APIs, no hacks, no special sauce. A simple, straight forward approach to making the initial interaction with the user as pleasant as possible.</p>
<p><em>References:</em></p>
<ul>
<li><a href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/c/econst/UIStatusBarStyleDefault">iPhone OS Reference Library UIApplication Class Reference UIStatusBarStyle</a></li>
<li><a href="http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/128-Managing_Devices/devices.html#//apple_ref/doc/uid/TP40007959-CH4-SW19">iPhone OS Reference Library iPhone Development Guide Capturing Screen Shots</a></li>
<li><a href="http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW44">Mac OS X Reference Library Threading Programming Guide Cocoa Perform Selector Sources</a></li>
<li><a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html">Mac OS X Reference Library NSNotificationsCenter Class Reference</a></li>
</ul>
<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=174160&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/iphone-dev-sessions-making-a-splash-screen/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/940906757c2b8631cab8b60f4adb61a3?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">ggeoffre</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2010/04/image-001.jpg" medium="image">
			<media:title type="html">Edit Projects plist File</media:title>
		</media:content>
	</item>
		<item>
		<title>iPhone Dev Sessions:  Adding Analytics to Your App</title>
		<link>http://gigaom.com/apple/iphone-dev-sessions-adding-analytics-to-your-app/</link>
		<comments>http://gigaom.com/apple/iphone-dev-sessions-adding-analytics-to-your-app/#comments</comments>
		<pubDate>Mon, 10 Aug 2009 14:50:41 +0000</pubDate>
		<dc:creator>Henry Balanon</dc:creator>
				<category><![CDATA[Walkthroughs]]></category>
		<category><![CDATA[bickboxx]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iphone dev sessions]]></category>
		<category><![CDATA[pinch media]]></category>

		<guid isPermaLink="false">http://theappleblog.com/?p=30352</guid>
		<description><![CDATA[Welcome to another episode of TheAppleBlog’s iPhone Dev Sessions. We left off with a drum app tutorial called Bickboxx. For this tutorial, we’re building off of the first Bickboxx project, so go back and finish it if you haven’t already. Or if you want to cheat, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=173214&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><img  title="2009-08-09_1936" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1936.png?w=200&h=200" alt="2009-08-09_1936" width="200" height="200" class=" alignleft" /></p>
<p class="excerpt">Welcome to another episode of <a href="http://theappleblog.com/tag/iphone-dev-sessions/">TheAppleBlog’s iPhone Dev Sessions</a>. We left off with a <a href="http://gigaom.com/apple/iphone-dev-sessions-create-a-drum-app/">drum app tutorial called Bickboxx</a>. For this tutorial, we’re building off of the first Bickboxx project, so go back and finish it if you haven’t already. Or if you want to cheat, grab the <a href="http://github.com/balanon/bickboxx/tree/master">Bickboxx code from Github</a>.</p>
<h3>The Story</h3>
<p>The Boss is happy we’ve released <a title="iPhone Dev Sessions: Create a Drum App" href="http://gigaom.com/apple/iphone-dev-sessions-create-a-drum-app/">Bickboxx, the iPhone drum app</a>, but now he wants to know how it’s doing. Not just sales-wise.</p>
<p>How many people use our app? How many times have they used the app? How much time do they spend using our app? How many users do we have in each city, state and country? How many illegal haxored versions are out there? How many people open the app once and never use it again?</p>
<p>Yikes. That’s a lot of questions.</p>
<p>Lucky for us, we don’t have to write hundreds of lines of code and roll our own analytics server to track the answer to these questions.</p>
<p>There are dozens of iPhone analytics APIs that will do all of the heavy lifting for us. <a href="http://www.flurry.com/">Flurry</a>, <a href="http://www.mobclix.com/">Mobclix</a>, and <a href="http://www.medialets.com/">Medialets</a> come to mind.</p>
<p>There isn’t a clear leader in iPhone analytics yet but for this tutorial we’ll be using <a href="http://www.pinchmedia.com/">Pinch Analytics</a>. It has comprehensive documentation and its reporting is detailed as well. <span id="more-173214"></span></p>
<h3>Signing Up for a Pinch Media Account</h3>
<p>The first thing you want to do is <a title="Pinch Media - Register" href="http://developer.pinchmedia.com/users/register">sign up for a Pinch Media account</a>. The first part of registration is the usual username/email/password page. The second part detailing your app takes you to this:</p>
<p><img  title="2009-08-09_1248" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1248.png?w=570&h=512" alt="2009-08-09_1248" width="570" height="512" class=" alignleft" /></p>
<p>Since Bickboxx isn’t a real app that you’ll be distributing, you don’t have to fill out any of this. You can skip this part by clicking the “I’ll do it later” button.</p>
<p>When you are adding analytics to your real-life app, I’ve filled out some sample data for you to go by. Note that if you don’t add an app into Pinch Media, you won’t be able to view any analytics reports.</p>
<h3>Download and Install the Pinch Media SDK</h3>
<p>After you’ve signed up for an account, <a href="http://developer.pinchmedia.com/analytics/library/download">download and unzip the SDK</a>.</p>
<p>Open up the Bickboxx project in Xcode. Drag the <strong>Beacon+FBConnect.h</strong> and <strong>Beacon.h</strong> files into the Classes directory in the Xcode project.</p>
<p><img  title="2009-08-09_1433" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1433.png?w=570&h=360" alt="2009-08-09_1433" width="570" height="360" class=" alignleft" /></p>
<p>Make sure the “Copy items into destination group’s folder (if needed)” checkbox is checked. Click Add. We do this so our code knows how to access the Pinch Media methods in the <strong>libPMAnalytics-rXX.a</strong> library.</p>
<p><img  title="2009-08-09_1430" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1430.png?w=570&h=360" alt="2009-08-09_1430" width="570" height="360" class=" alignleft" /></p>
<p>We’ll need to import the <strong>libPMAnalytics-rXX.a</strong> library next. Do this by dragging the <strong>libPMAnalytics-rXX.a</strong> file to the Frameworks folder in Xcode. Again, make sure the “Copy items into destination group’s folder (if needed)” checkbox is checked. Click Add.</p>
<p><img  title="2009-08-09_1433a" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1433a.png?w=570&h=360" alt="2009-08-09_1433a" width="570" height="360" class=" alignleft" /></p>
<h3>Install the Supporting SDKs</h3>
<p>We need a few more frameworks to get going. We may not use these frameworks directly, but Pinch Analytics does.</p>
<p>Ctrl-Click the Frameworks folder and choose <strong>Add → Existing Frameworks&#8230;</strong></p>
<p><img  title="2009-08-09_1441" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1441.png?w=528&h=267" alt="2009-08-09_1441" width="528" height="267" class=" alignleft" /></p>
<p>Select <strong>libsqlite3.dylib</strong> and click Add.</p>
<p><img  title="2009-08-09_1442" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1442.png?w=338&h=534" alt="2009-08-09_1442" width="338" height="534" class=" alignleft" /></p>
<p>Do the same for the <strong>SystemConfiguration.framework</strong>.</p>
<p><img  title="2009-08-09_1501" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1501.png?w=338&h=534" alt="2009-08-09_1501" width="338" height="534" class=" alignleft" /></p>
<p>Lastly, do the same for <strong>CoreLocation.framework</strong>.</p>
<p><img  title="2009-08-09_1502" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1502.png?w=338&h=534" alt="2009-08-09_1502" width="338" height="534" class=" alignleft" /></p>
<p>Build the project to make sure everything is in place. It should compile. Got it? Good.</p>
<h3>Adding the Pinch Analytics Code</h3>
<p>Add this import statement for the <strong>Beacon.h</strong> file into <strong>BickBoxxAppDelegate.h</strong>.</p>
<p><pre class="brush: csharp;">
#import “Beacon.h”
</pre></p>
<p>Adding this will allow us access to the Pinch Analytics methods from inside our <strong>BickBoxxAppDelegate.m</strong> file. Your <strong>BickboxxAppDelegate.h</strong> file should now look like this. Our change is in line 2.</p>
<p><pre class="brush: csharp;">
#import &lt;UIKit/UIKit.h&gt;
#import &quot;Beacon.h&quot;

@class BickBoxxViewController;

@interface BickBoxxAppDelegate : NSObject &lt;UIApplicationDelegate&gt; {
  UIWindow *window;
  BickBoxxViewController *viewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet BickBoxxViewController *viewController;

@end
</pre></p>
<p>Open up <strong>BickBoxxAppDelegate.m</strong> and locate the <code>applicationDidFinishLaunching</code> method. Add this line of code.</p>
<p><pre class="brush: csharp;">
NSString *applicationCode = @"REPLACE THIS WITH YOUR APPLICATION CODE";
</pre></p>
<p>Replace the <code>REPLACE THIS WITH YOUR APPLICATION CODE</code> with your Application Code from Pinch Media. You can find your application code in <a href="http://developer.pinchmedia.com/applications/">your Pinch Media account</a>.</p>
<p><img  title="2009-08-09_1559" src="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1559.png?w=570&h=327" alt="2009-08-09_1559" width="570" height="327" class=" alignleft" /></p>
<p>This is your unique ID that Pinch Media uses to identify which app is sending data to them. If you opted to not setup an app during registration, you need to do this to get an Application Code. If you don’t put in a valid Application Code, you won’t get any analytics reports and you’re wasting your time.</p>
<p>We’re going to use this <code>applicationCode</code> NSString to activate our analytics beacon. Add this line of code to the <code>applicationDidFinishLaunching</code> method.</p>
<p><pre class="brush: csharp;">
[Beacon initAndStartBeaconWithApplicationCode:applicationCode
    useCoreLocation:YES useOnlyWiFi:NO];
</pre></p>
<p>This fires up the analytics code when the app launches. Note that we’re sending in the <code>applicationCode</code> NSString that we inserted in the previous step. Also note the <code>useCoreLocation</code> parameter. You can set this to <code>YES</code> or <code>NO</code> depending on whether you want to capture location statistics.</p>
<p>Use this with caution. If you think you’ll offend your users by asking for their location, set this to <code>NO</code>.</p>
<p>Another parameter is <code>useOnlyWiFi</code>. Not everyone in the world has an unlimited data plan. They&#8217;ll be none to happy if your app is sending data over the mobile network when they don’t want it to.</p>
<p>Like the <code>useCoreLocation</code> parameter, use this parameter with caution. If set to <code>YES</code>, the analytics data will be sent to Pinch Media only when they’re connected to Wi-Fi. This way, the people who pay their mobile carrier per kilobyte won’t get mad. The downside is that you will miss usage statistics if they never connect to Wi-Fi.</p>
<p>If you’re not worried about being responsible for someone’s data overages, set this to <code>NO</code>.</p>
<p>Your code in <strong>BickBoxxAppDelegate.m</strong> for the <code>applicationDidFinishLaunching</code> method should now look like this.</p>
<p><pre class="brush: csharp;">
- (void)applicationDidFinishLaunching:(UIApplication *)application {

	// New code below this
	NSString *applicationCode = @"REPLACE THIS WITH YOUR APPLICATION CODE";
  [Beacon initAndStartBeaconWithApplicationCode:applicationCode
								 useCoreLocation:YES useOnlyWiFi:NO];

  // Old code below this
	[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];

  // Override point for customization after app launch
  [window addSubview:viewController.view];
  [window makeKeyAndVisible];
}
</pre></p>
<p>Finally, when we exit the app or your app crashes (your apps never crash right?), we need to stop the analytics beacon.</p>
<p>Add this method to the <strong>BickBoxxAppDelegate.m</strong> file.</p>
<p><pre class="brush: csharp;">
- (void)applicationWillTerminate:(UIApplication *)application {
  [[Beacon shared] endBeacon];
}
</pre></p>
<p>Build and run your app.</p>
<h3>You’re Done!</h3>
<p>That’s it &#8212; you’re done! Go to lunch and have a sandwich. Nothing’s changed to the user except it’s going to ask if it’s okay that Bickboxx uses their location. You can now login to Pinch Media’s site and see all your pretty statistics and graphs. Worth noting is that the data isn’t real-time &#8212; it’s only updated twice a day.</p>
<h3>Homework</h3>
<p>The Boss is happy now that we can measure the performance of our app. He wants more detail on which buttons are pressed the most. You can do this by adding sub-beacons, which you can read about at <a href="http://resources.pinchmedia.com/docs/Pinch_Analytics/">the documentation site</a>.</p>
<h3>BickBoxx On Github and the iTunes App Store</h3>
<p><a href="http://gigaom.com/apple/iphone-dev-sessions-create-a-drum-app/">Like last time</a>, the code is <a href="http://github.com/balanon/bickboxx/tree/master">open-sourced on Github</a>. You can check your code against the code here if you start to stumble.</p>
<p>We’re here to show you how to build actual apps. You can download the app as it’s built at the <a href="http://a.bickbot.com/boxx">iTunes App Store</a>. More info on the open-source/open-tutorialized efforts on <a href="http://bickbot.com/bickboxx">the BickBoxx website</a>.</p>
<p><strong>Related research and analysis from GigaOM Pro:</strong><br />Subscriber content. <a href="http://pro.gigaom.com/?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=173214+iphone-dev-sessions-adding-analytics-to-your-app&utm_content=balanon">Sign up for a free trial</a>.</p><ul><li><a href="http://pro.gigaom.com/2011/01/mobile-q4-all-eyes-were-on-android-4g-and-the-rising-tablet-tide/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=173214+iphone-dev-sessions-adding-analytics-to-your-app&utm_content=balanon">Mobile Q4: All Eyes Were on Android, 4G and the Rising Tablet&nbsp;Tide</a></li><li><a href="http://pro.gigaom.com/2010/12/report-a-mobile-video-market-overview/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=173214+iphone-dev-sessions-adding-analytics-to-your-app&utm_content=balanon">Report: A Mobile Video Market&nbsp;Overview</a></li><li><a href="http://pro.gigaom.com/2010/10/in-q3-the-tablet-and-4g-were-the-big-stories/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=173214+iphone-dev-sessions-adding-analytics-to-your-app&utm_content=balanon">In Q3, the Tablet and 4G Were the Big&nbsp;Stories</a></li></ul><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=173214&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/iphone-dev-sessions-adding-analytics-to-your-app/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e0c66e7aa8ea6f9b5fdd72fb70545d4c?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">balanon</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1936.png" medium="image">
			<media:title type="html">2009-08-09_1936</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1248.png?w=570" medium="image">
			<media:title type="html">2009-08-09_1248</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1433.png?w=570" medium="image">
			<media:title type="html">2009-08-09_1433</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1430.png?w=570" medium="image">
			<media:title type="html">2009-08-09_1430</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1433a.png?w=570" medium="image">
			<media:title type="html">2009-08-09_1433a</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1441.png" medium="image">
			<media:title type="html">2009-08-09_1441</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1442.png" medium="image">
			<media:title type="html">2009-08-09_1442</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1501.png" medium="image">
			<media:title type="html">2009-08-09_1501</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1502.png" medium="image">
			<media:title type="html">2009-08-09_1502</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/08/2009-08-09_1559.png?w=570" medium="image">
			<media:title type="html">2009-08-09_1559</media:title>
		</media:content>
	</item>
		<item>
		<title>iPhone Dev Sessions: Create a Drum App</title>
		<link>http://gigaom.com/apple/iphone-dev-sessions-create-a-drum-app/</link>
		<comments>http://gigaom.com/apple/iphone-dev-sessions-create-a-drum-app/#comments</comments>
		<pubDate>Mon, 11 May 2009 18:00:10 +0000</pubDate>
		<dc:creator>Henry Balanon</dc:creator>
				<category><![CDATA[CNN Mobile]]></category>
		<category><![CDATA[SYN Feature Enterprise]]></category>
		<category><![CDATA[Walkthroughs]]></category>
		<category><![CDATA[bickboxx]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iphone dev sessions]]></category>

		<guid isPermaLink="false">http://theappleblog.com/?p=22658</guid>
		<description><![CDATA[You’ve seen all the different drum apps, right? Well, they’re really easy to make. In this iPhone Dev Sessions article, I want to teach you how to make Bickboxx, an actual app that’s in the iTunes App Store. Grab Bickboxx (FREE) from the iTunes App Store [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=172691&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><img  title="BickBoxx-1" src="http://gigapple.files.wordpress.com/2009/05/bickboxx-1.jpg?w=250&h=248" alt="BickBoxx-1" width="250" height="248" class=" alignleft" /></p>
<p class="excerpt">You’ve seen all the different drum apps, right? Well, they’re really easy to make. In this <a href="http://theappleblog.com/tag/iphone-dev-sessions/">iPhone Dev Sessions</a> article, I want to teach you how to make Bickboxx, an actual app that’s in the <a href="http://a.bickbot.com/boxx">iTunes App Store</a>.</p>
<p>Grab <a href="http://a.bickbot.com/boxx">Bickboxx</a> (FREE) from the iTunes App Store if you want to see this puppy in action so you have an idea of what you&#8217;re building. Also, I’ve opened up the <a href="http://github.com/balanon/bickboxx/">source code</a> for free at Github. Feel free to download it, report issues, or even fork your own version and change it as you see fit.</p>
<p>More info on the open-source community project at <a href="http://bickbot.com/bickboxx/">Bickbot&#8217;s Bickboxx page</a>.</p>
<p>Note: You don’t need to download the code from Github to get through the tutorial.</p>
<h3>An On-going Project</h3>
<p>I plan on adding more tutorials with enhancements to this project. Here are a couple of things that could be featured in future iPhone Dev Sessions.</p>
<ul>
<li>Key logger</li>
<li>Adding analytics tracking</li>
<li>Adding application preferences</li>
<li>Track recorder and editor</li>
<li>Vibration feedback</li>
<li>Add your own custom sounds</li>
<li>Access your iPod library as a background track</li>
</ul>
<p>Leave a comment with other enhancements you want to learn.</p>
<p>OK, let&#8217;s get to creating Bickboxx! <span id="more-172691"></span></p>
<h3>Get Started</h3>
<p>Create a new View-based project in XCode. Name the project &#8220;Bickboxx&#8221;.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/createnewproject.png?w=604" alt="" class=" alignleft" /></p>
<p><a href="http://a.theappleblog.com/downloads/BickboxxAssets.zip">Download this zip file</a> and unzip it. These are all the sounds, images, and icons you need for Bickboxx. Drag all these files to the Resources. Hat tip to <a href="http://twitter.com/ellenich">John Ellenich</a> for the graphics/sounds.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/dragtoresources.png?w=604" alt="" class=" alignleft" /></p>
<p>You need to copy the item to the project’s directory, so put a check mark next to “Copy items into destination group’s folder (if needed).” Your settings should look similar to this. Click Add.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/copyitems.png?w=604" alt="" class=" alignleft" /></p>
<h3>Adding the background image in Interface Builder</h3>
<p>Double-click <em><strong>BickboxxViewController.xib</strong></em> to open it in Interface Builder. Drag an Image View (<code>UIImageView</code>) from the Library to the View window. This will act as a placement holder for our background image.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/image-5101.png?w=510&amp;h=415" alt="" class=" alignleft" /></p>
<p>Bring up the Attributes Inspector. Set the Image to <code>Background.png</code>.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/background_png.png?w=604" alt="" class=" alignleft" /></p>
<h3>Creating the Button in Interface Builder</h3>
<p>Drag a Round Rect Button (<code>UIButton</code>) to the View.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/dragbutton.png?w=604" alt="" class=" alignleft" /></p>
<p>Bring up the Attributes Inspector. We don’t want the button to look like an ugly white rectangle. Set the Type to Custom.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/custombutton.png?w=604" alt="" class=" alignleft" /></p>
<p>Further down the Attributes Inspector, set the button’s state to Normal (or Default State Configuration depending on your version of Xcode). This is what the button looks like when it’s not doing anything.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/normalbutton.png?w=604" alt="" class=" alignleft" /></p>
<p>Set the button’s Image to <code>B Inactive.png</code>.  You need to resize the button in the View to make sure the “B” button is fully shown.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/binactive.png?w=604" alt="" class=" alignleft" /></p>
<p>Now, change the button’s state to Highlighted (or Highlighted State Configuration depending on your version of Xcode). This is what the button looks like when it’s pressed down.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/bactive.png?w=604" alt="" class=" alignleft" /></p>
<p>Set the button’s Image to <code>B Active.png</code>.</p>
<p>Drag another Round Rect Button (<code>UIButton</code>) to the View and repeat this section for the letters “E”, “A”, and “T”. Your View should now look like this:</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/beatfull.png?w=604" alt="" class=" alignleft" /></p>
<p>Close Interface Builder for now.</p>
<p>Build and Go to make sure everything is still working. Touch the buttons, and they should light up.</p>
<h3>Adding the Sounds Code</h3>
<p>We have an interface that doesn’t do anything. Let’s fix that. The audio framework we need isn’t added by default. We have to add the AudioToolbox framework.</p>
<p>Control+Click the Frameworks folder on the left. Go to <strong>Add → Existing Frameworks&#8230;</strong></p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/addframework.png?w=604" alt="" class=" alignleft" /></p>
<p>Select the <em><strong>AudioToolbox.framework</strong></em> from <em><strong>/System/Library/Frameworks</strong></em>.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/audiotoolbox.png?w=604" alt="" class=" alignleft" /></p>
<p>Click OK and add it to the project.</p>
<p>Open <em><strong>BickboxxViewController.h</strong></em> and add this code to it.</p>
<p><pre class="brush: csharp;">

#import &lt;UIKit/UIKit.h&gt;
#import &lt;AudioToolbox/AudioServices.h&gt;

@interface BickboxxViewController : UIViewController {
    CFURLRef        bNoteFileURLRef;
    SystemSoundID    bNoteFileObject;
    CFURLRef        eNoteFileURLRef;
    SystemSoundID    eNoteFileObject;
    CFURLRef        aNoteFileURLRef;
    SystemSoundID    aNoteFileObject;
    CFURLRef        tNoteFileURLRef;
    SystemSoundID    tNoteFileObject;
}

@property (readwrite)    CFURLRef        bNoteFileURLRef;
@property (readonly)    SystemSoundID    bNoteFileObject;
@property (readwrite)    CFURLRef        eNoteFileURLRef;
@property (readonly)    SystemSoundID    eNoteFileObject;
@property (readwrite)    CFURLRef        aNoteFileURLRef;
@property (readonly)    SystemSoundID    aNoteFileObject;
@property (readwrite)    CFURLRef        tNoteFileURLRef;
@property (readonly)    SystemSoundID    tNoteFileObject;

@end

</pre></p>
<p>At the top, we’re referencing <strong>AudioServices.h</strong> from the AudioToolbox framework we imported earlier.</p>
<p>Below that is the declaration of properties for four sounds for the “B”, “E”, “A” and “T” buttons.</p>
<p><code>bNoteFileURLRef</code> is the file location reference for the <code>bNoteFileObject</code>. This is the sound the “B” button will make.</p>
<p>These are the properties for the “E”, “A” and “T” sounds as well.</p>
<h3>The BickboxxViewController.m File</h3>
<p>Open <em><strong>BickboxxViewController.m</strong></em>. We need to synthesize the getters/setters for our properties.</p>
<p>You can do this by adding this after <code>@implementation BickBoxxViewController</code>:</p>
<p><pre class="brush: csharp;">

@synthesize bNoteFileURLRef, bNoteFileObject, eNoteFileURLRef,
eNoteFileObject, aNoteFileURLRef, aNoteFileObject,
tNoteFileURLRef, tNoteFileObject;

</pre></p>
<h3>Changing the viewDidLoad Method</h3>
<p>Locate the <code>viewDidLoad</code> method. It will be commented out. You want to uncomment it to activate it.</p>
<p>The <code>viewDidLoad</code> method gets called after all the UI components are created. This is a good place for any startup code you need your app to perform. In this case, we’ll need to set our properties to the correct sounds.</p>
<p>The first thing we need to do in <code>viewDidLoad</code> is get the main bundle for the app. The main bundle allows you to use a folder hierarchy to organize and locate many types of application resources including images, sounds, localized strings, and executable code.</p>
<p>After <code>[super viewDidLoad];</code>, add this code to get the main bundle for the app.</p>
<p><pre class="brush: csharp;">

// Get the main bundle for the app
CFBundleRef mainBundle;
mainBundle = CFBundleGetMainBundle ();

</pre></p>
<p>To build the sound for the “B” button, we need to get the path of the sound file we want to play. The name of the sound file is <em><strong>B.aifc</strong></em>. This is the code to get the URL to the found file to play. Put this code after the code where you get the main bundle.</p>
<p><pre class="brush: csharp;">

// Get the URL to the sound file to play
bNoteFileURLRef  =    CFBundleCopyResourceURL (
                                             mainBundle,
                                             CFSTR ("B"),
                                             CFSTR ("aifc"),
                                             NULL
                                             );

</pre></p>
<p>Note that valid system sound packages are <code>.wav</code>, <code>.aif</code> and <code>.caf</code> files.</p>
<p>Now that we have <code>bNoteFileURLRef</code> set we can associate the sound file with the system sound object <code>bNoteFileObject</code>. The <code>AudioServicesPlaySystemSound</code> function lets you very simply play short sound files.</p>
<p>Add this code after the code that gets the sound file URL.</p>
<p><pre class="brush: csharp;">

// Create a system sound object representing the sound file
AudioServicesCreateSystemSoundID (bNoteFileURLRef, &bNoteFileObject);

</pre></p>
<p>We finished loading up the sound for the &#8220;B&#8221; button. We’ll need to load up the sounds for the “E”, “A” and “T” buttons.</p>
<p>Try to code this part yourself. If you get stuck, the <code>viewDidLoad</code> method should look like this when you&#8217;re done.</p>
<p><pre class="brush: csharp;">

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    // Get the main bundle for the app
    CFBundleRef mainBundle;
    mainBundle = CFBundleGetMainBundle ();

    // Get the URL to the sound file to play
    bNoteFileURLRef  =    CFBundleCopyResourceURL (
                                                 mainBundle,
                                                 CFSTR ("B"),
                                                 CFSTR ("aifc"),
                                                 NULL
                                                 );

    // Create a system sound object representing the sound file
    AudioServicesCreateSystemSoundID (bNoteFileURLRef, &bNoteFileObject);

    // Get the URL to the sound file to play
    eNoteFileURLRef  =    CFBundleCopyResourceURL (
                                                 mainBundle,
                                                 CFSTR ("E"),
                                                 CFSTR ("aifc"),
                                                 NULL
                                                 );

    // Create a system sound object representing the sound file
    AudioServicesCreateSystemSoundID (eNoteFileURLRef, &eNoteFileObject);

    // Get the URL to the sound file to play
    aNoteFileURLRef  =    CFBundleCopyResourceURL (
                                                 mainBundle,
                                                 CFSTR ("A"),
                                                 CFSTR ("aifc"),
                                                 NULL
                                                 );
    // Create a system sound object representing the sound file
    AudioServicesCreateSystemSoundID (aNoteFileURLRef, &aNoteFileObject);

    // Get the URL to the sound file to play
    tNoteFileURLRef  =    CFBundleCopyResourceURL (
                                                 mainBundle,
                                                 CFSTR ("T"),
                                                 CFSTR ("aifc"),
                                                 NULL
                                                 );

    // Create a system sound object representing the sound file
    AudioServicesCreateSystemSoundID (tNoteFileURLRef, &tNoteFileObject);
}

</pre></p>
<h3>Creating Our IBActions</h3>
<p>Our BEAT buttons need to be associated with IBActions to make them do something. First, let’s declare the methods. Open <em><strong>BickboxxViewController.h</strong></em> and add this code before the <code>@end</code> line.</p>
<p><pre class="brush: csharp;">
- (IBAction)bSound:(id)sender;
- (IBAction)eSound:(id)sender;
- (IBAction)aSound:(id)sender;
- (IBAction)tSound:(id)sender;
</pre></p>
<p>Your <em><strong>BickboxxViewController.h</strong></em> should now look like:</p>
<p><pre class="brush: csharp;">

#import &lt;UIKit/UIKit.h&gt;
#import &lt;AudioToolbox/AudioServices.h&gt;

@interface BickBoxxViewController : UIViewController {
    CFURLRef        bNoteFileURLRef;
    SystemSoundID    bNoteFileObject;
    CFURLRef        eNoteFileURLRef;
    SystemSoundID    eNoteFileObject;
    CFURLRef        aNoteFileURLRef;
    SystemSoundID    aNoteFileObject;
    CFURLRef        tNoteFileURLRef;
    SystemSoundID    tNoteFileObject;
}

@property (readwrite)    CFURLRef        bNoteFileURLRef;
@property (readonly)    SystemSoundID    bNoteFileObject;
@property (readwrite)    CFURLRef        eNoteFileURLRef;
@property (readonly)    SystemSoundID    eNoteFileObject;
@property (readwrite)    CFURLRef        aNoteFileURLRef;
@property (readonly)    SystemSoundID    aNoteFileObject;
@property (readwrite)    CFURLRef        tNoteFileURLRef;
@property (readonly)    SystemSoundID    tNoteFileObject;

// The new code you added
- (IBAction)bSound:(id)sender;
- (IBAction)eSound:(id)sender;
- (IBAction)aSound:(id)sender;
- (IBAction)tSound:(id)sender;

@end

</pre></p>
<p>Close the file and open <em><strong>BickboxxViewController.m</strong></em>. Add the implementation to make the IBAction methods make the appropriate system sounds by invoking the <code>AudioServicesPlaySystemSound</code> method.</p>
<p>To play the “B” sound, the implemented method should make a call to <code>AudioServicesPlaySystemSound</code> and use the <code>bNoteFileObject</code> we created above. Add this after the property synthesis code:</p>
<p><pre class="brush: csharp;">
- (IBAction)bSound:(id)sender {
AudioServicesPlaySystemSound (self.bNoteFileObject);
}
</pre></p>
<p>Add similar implementations for the “E”, “A” and “T” sounds as well.</p>
<p>For reference, the top of <em><strong>BickboxxViewController.m</strong></em> should look like:</p>
<p><pre class="brush: csharp;">

#import "BickBoxxViewController.h" 

@implementation BickBoxxViewController

@synthesize bNoteFileURLRef, bNoteFileObject, eNoteFileURLRef,
eNoteFileObject, aNoteFileURLRef, aNoteFileObject,
tNoteFileURLRef, tNoteFileObject;

- (IBAction)bSound:(id)sender {
    AudioServicesPlaySystemSound (self.bNoteFileObject);
}

- (IBAction)eSound:(id)sender {
    AudioServicesPlaySystemSound (self.eNoteFileObject);
}

- (IBAction)aSound:(id)sender {
    AudioServicesPlaySystemSound (self.aNoteFileObject);
}

- (IBAction)tSound:(id)sender {
    AudioServicesPlaySystemSound (self.tNoteFileObject);
}

</pre></p>
<p>For the last piece of code, we need to clean up our mess so we don’t have memory leaks. At the bottom of <em><strong>BickboxxViewController.m</strong></em>, add these lines to your <code>dealloc</code> method:</p>
<p><pre class="brush: csharp;">

- (void)dealloc {
    [super dealloc];
    AudioServicesDisposeSystemSoundID (self.bNoteFileObject);
    AudioServicesDisposeSystemSoundID (self.eNoteFileObject);
    AudioServicesDisposeSystemSoundID (self.aNoteFileObject);
    AudioServicesDisposeSystemSoundID (self.tNoteFileObject);
    CFRelease (bNoteFileURLRef);
    CFRelease (eNoteFileURLRef);
    CFRelease (aNoteFileURLRef);
    CFRelease (tNoteFileURLRef);
}

</pre></p>
<p>We&#8217;re done coding. Build and Go the project to make sure nothing is on fire. Your buttons won&#8217;t make any sounds yet. We&#8217;ll need to link our code to our interface.</p>
<h3>Linking the buttons to the code in Interface Builder</h3>
<p>Now that our code is done, we can link our buttons to our code. We’ll start with the “B” button link it with the <code>bsound</code> method. To do this, open up <em><strong>BickboxxViewController.xib</strong></em>.</p>
<p>Control+Click on the File’s Owner object so we can link our “B” button to our <code>bsound</code>.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/rightclickfilesowner.png?w=604" alt="" class=" alignleft" /></p>
<p>Drag from the <code>bSound</code> in File’s Owner to the “B” button in the View.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/fromfilesownertobutton.png?w=604" alt="" class=" alignleft" /></p>
<p>An overlay should pop up. Choose Touch Down. The normal default is to execute the action when the finger is lifted from the button. We don’t want that. Soundboards don’t work that way. This will call the <code>bSound</code> IBAction method when the button is pressed down.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/touchdown.png?w=604" alt="" class=" alignleft" /></p>
<p>Do this linking with the rest of the buttons. When you’re done, Control+Clicking File’s owner should look like this.</p>
<p><img src="http://gigapple.files.wordpress.com/2009/04/allbuttonslinked.png?w=604" alt="" class=" alignleft" /></p>
<p>Here&#8217;s a video of me using Bickboxx to practice for my opening act for Paul Oakenfold.</p>
<span style="text-align:center; display: block;"><a href="http://gigaom.com/apple/iphone-dev-sessions-create-a-drum-app/"><img src="http://img.youtube.com/vi/OBUA_cpSm1A/2.jpg" alt="" /></a></span>
<h3>You’re done!</h3>
<p>That’s it &#8212; you’re done! Compile and run this and you’ll be DJ-ing parties with Moby in no time.</p>
<p>Again, you can download the source from social coding site <a href="http://github.com/balanon/bickboxx/">Github</a>. Feel free to file issues here if the code needs fixing or enhancing.</p>
<h3>Homework</h3>
<p>Are you ready to apply your newfound knowledge? Solidify it with this extra credit assignment.</p>
<p>Your homework: Add a new button and a new sound to the project.</p>
<p>If there are any typos, problems, suggestions, or questions, let me know here in the comments.</p>
<p><strong>Related research and analysis from GigaOM Pro:</strong><br />Subscriber content. <a href="http://pro.gigaom.com/?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172691+iphone-dev-sessions-create-a-drum-app&utm_content=balanon">Sign up for a free trial</a>.</p><ul><li><a href="http://pro.gigaom.com/2011/01/mobile-q4-all-eyes-were-on-android-4g-and-the-rising-tablet-tide/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172691+iphone-dev-sessions-create-a-drum-app&utm_content=balanon">Mobile Q4: All Eyes Were on Android, 4G and the Rising Tablet&nbsp;Tide</a></li><li><a href="http://pro.gigaom.com/2010/12/report-a-mobile-video-market-overview/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172691+iphone-dev-sessions-create-a-drum-app&utm_content=balanon">Report: A Mobile Video Market&nbsp;Overview</a></li><li><a href="http://pro.gigaom.com/2010/10/in-q3-the-tablet-and-4g-were-the-big-stories/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172691+iphone-dev-sessions-create-a-drum-app&utm_content=balanon">In Q3, the Tablet and 4G Were the Big&nbsp;Stories</a></li></ul><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=172691&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/iphone-dev-sessions-create-a-drum-app/feed/</wfw:commentRss>
		<slash:comments>56</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e0c66e7aa8ea6f9b5fdd72fb70545d4c?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">balanon</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/05/bickboxx-1.jpg" medium="image">
			<media:title type="html">BickBoxx-1</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/createnewproject.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/dragtoresources.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/copyitems.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/image-5101.png?w=510&#38;h=415" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/background_png.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/dragbutton.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/custombutton.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/normalbutton.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/binactive.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/bactive.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/beatfull.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/addframework.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/audiotoolbox.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/rightclickfilesowner.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/fromfilesownertobutton.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/touchdown.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2009/04/allbuttonslinked.png" medium="image" />
	</item>
		<item>
		<title>iPhone Dev Sessions: Create a Navigation-Based Application</title>
		<link>http://gigaom.com/apple/iphone-dev-sessions-create-a-navigation-based-application/</link>
		<comments>http://gigaom.com/apple/iphone-dev-sessions-create-a-navigation-based-application/#comments</comments>
		<pubDate>Wed, 15 Apr 2009 19:30:50 +0000</pubDate>
		<dc:creator>Keun Lee</dc:creator>
				<category><![CDATA[CNN Big Tech]]></category>
		<category><![CDATA[NYT Enterprise]]></category>
		<category><![CDATA[SYN Feature Enterprise]]></category>
		<category><![CDATA[Walkthroughs]]></category>
		<category><![CDATA[Apps]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iphone dev sessions]]></category>
		<category><![CDATA[iPod Touch]]></category>

		<guid isPermaLink="false">http://theappleblog.com/?p=21018</guid>
		<description><![CDATA[In this tutorial, you will learn how to do the following: Create and run a Navigation-Based Application from XCode Create and add a user interface, designed in Interface Builder, as a sub-view to a navigation based application Navigate to sub-views from a UITableView Allow sub-views to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=172588&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In this tutorial, you will learn how to do the following:</p>
<ul>
<li>Create and run a Navigation-Based Application from XCode</li>
<li>Create and add a user interface, designed in Interface Builder, as a sub-view to a navigation based application</li>
<li>Navigate to sub-views from a UITableView</li>
<li>Allow sub-views to access application data</li>
</ul>
<h3>Creating and Running a Navigation-Based Application in XCode</h3>
<p>Let&#8217;s start off by opening up XCode and creating a Navigation-Based Application.</p>
<p style="text-align: center;"><img  title="001" src="http://gigapple.files.wordpress.com/2009/04/001.png?w=604" alt="001" class=" alignleft" /></p>
<p>Click <strong>Choose&#8230;</strong> and give your application the name <strong>BasicNavigation</strong>. Once completed, your project window should look like this.</p>
<p style="text-align: center;"><img  title="002" src="http://gigapple.files.wordpress.com/2009/04/002.png?w=604" alt="002" class=" alignleft" /></p>
<p>At this point, if you click &#8220;Build and Go&#8221; and have your project selected to run on the iPhone simulator, you should see the application launch and display a bare UITableView, with undefined row elements. No worries, this is going to change very soon. Your app at this point should look like the following below. <span id="more-172588"></span></p>
<p style="text-align: center;"><img  title="003" src="http://gigapple.files.wordpress.com/2009/04/003.png?w=309&h=594" alt="003" width="309" height="594" class=" alignleft" /></p>
<h3>Adding a Sub-view (Designed in Interface Builder) to a UITableView</h3>
<p>We are now going to add a sub-view to our application. This sub-view will consist of three key elements.</p>
<ul>
<li>A Header File (*.h file extension) &#8212; Used for defining methods and variables to be used by an accompanied implementation file.</li>
<li>An Implementation File (*.m file extension) &#8212; Used for implementing methods and accessing variables defined in an accompanied header file. This is where we will place code for view specific logic and functionality.</li>
<li>An Interface File (*.xib extension) &#8212; Used for defining the visual look of the view, using Interface Builder.</li>
</ul>
<p>In XCode, within the project area on the left, right-click on the <strong>Classes</strong> folder and select <strong>Add</strong>, then <strong>New File&#8230;</strong>. You will be presented with the following dialogue.</p>
<p style="text-align: center;"><img  title="004" src="http://gigapple.files.wordpress.com/2009/04/004.png?w=604" alt="004" class=" alignleft" /></p>
<p>Make sure you&#8217;ve selected <strong>Cocoa Touch Classes</strong> on the left and select the file template for <strong>UIViewController subclass</strong> as illustrated above, and click Next. You will be presented with a dialogue in which you will assign a name for this asset. Name this file <strong>SubViewOneController.m</strong> and make sure the checkbox for <strong>Also create &#8216;SubViewOneController.h&#8217;</strong> is checked as well. Click <strong>Finish</strong> when this is done. The dialogue should look like the following, before clicking on <strong>Finish</strong>.</p>
<p style="text-align: center;"><img  title="005" src="http://gigapple.files.wordpress.com/2009/04/005.png?w=604" alt="005" class=" alignleft" /></p>
<p>At this point, you will see two additional files in the <strong>Classes</strong> folder that we&#8217;ve just added. So far we&#8217;ve added a header file (SubViewOneController.h) and an implementation file (SubViewOneController.m), which takes care of two out of three key elements. We&#8217;ll now add the last element here before moving on towards implementation.</p>
<p>In XCode, right-click the <strong>Resources</strong> folder and select <strong>Add</strong>, then <strong>New File&#8230;</strong>. On the left, select <strong>User Interfaces</strong> and select <strong>View XIB</strong> and click next. In the next dialogue, you will give this user interface a name. Type <strong>SubViewOne.xib</strong> under File Nam&#8221; and click <strong>Finish</strong>. These steps are illustrated below.</p>
<p style="text-align: center;"><img  title="006" src="http://gigapple.files.wordpress.com/2009/04/006.png?w=604" alt="006" class=" alignleft" /></p>
<p style="text-align: center;"><img  title="007" src="http://gigapple.files.wordpress.com/2009/04/007.png?w=604" alt="007" class=" alignleft" /></p>
<p>The contents of your project window should now look similar to the illustration below.</p>
<p style="text-align: center;"><img  title="008" src="http://gigapple.files.wordpress.com/2009/04/008.png?w=478&h=393" alt="008" width="478" height="393" class=" alignleft" /></p>
<p>Open the file <strong>SubViewOneController.h</strong> and add the following code:</p>
<p><pre class="brush: csharp;">
#import &lt;UIKit/UIKit.h&gt;

@interface SubViewOneController : UIViewController {
	IBOutlet UILabel *label;
	IBOutlet UIButton *button;
}

@property (retain,nonatomic) IBOutlet UILabel *label;
@property (retain,nonatomic) IBOutlet UIButton *button;

- (IBAction) OnButtonClick:(id) sender;

@end
</pre></p>
<p>Open the file &#8220;SubViewOneController.m&#8221; and add the following code:</p>
<p><pre class="brush: csharp;">
#import "SubViewOneController.h"

@implementation SubViewOneController

@synthesize label, button;

- (id) init {
	self = [super init];
	if (self != nil) {
		// set the title of this view
		self.title = NSLocalizedString(@"Subview One", @"");
	}
	return self;
}

- (IBAction) OnButtonClick:(id) sender {
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

- (void)dealloc {
    [super dealloc];
}

@end
</pre></p>
<p>What we&#8217;ve done thus far is write a bit of view controller code. In our code, we&#8217;ve declared a variable for a <code>UILabel</code> and a <code>UIButton</code>. We&#8217;ve also created a stubbed handler method for responding on the button click action. What we haven&#8217;t done yet is create a user interface to go with our view controller code. Let&#8217;s go ahead do that now.</p>
<p>In the project window, let&#8217;s expand the <strong>Resources</strong> node, and double click on the file <strong>SubViewOne.xib</strong>. You will then see Interface Builder open this file and be presented with a blank View file. In the menu bar, click on <strong>Tools</strong>, then <strong>Library</strong>. When the Library window opens, click on the <strong>Inputs &amp; Values</strong> node. The Library window will look this.</p>
<p style="text-align: center;"><img  title="009" src="http://gigapple.files.wordpress.com/2009/04/009.png?w=315&h=759" alt="009" width="315" height="759" class=" alignleft" /></p>
<p>Drag a UILabel and a UIButton such that your view mimics the following interface.</p>
<p style="text-align: center;"><img  title="010" src="http://gigapple.files.wordpress.com/2009/04/010.png?w=604" alt="010" class=" alignleft" /></p>
<p>At this point, if you have not saved and built your project, please do so by going back into XCode and clicking the <strong>Build</strong> button. If all is well, everything will build successfully. We&#8217;re not done just yet, so let&#8217;s head back to Interface Builder.</p>
<p>Highlight <strong>File&#8217;s Owner</strong> and then from the menu bar, click on <strong>Tools</strong>, then <strong>Identity Inspector</strong>. In the <strong>Class</strong> text input, type or scroll down to the menu option that says <strong>SubViewOneController</strong>. Your view properties should now look similar to the following.</p>
<p style="text-align: center;"><img  title="011" src="http://gigapple.files.wordpress.com/2009/04/011.png?w=604" alt="011" class=" alignleft" /></p>
<p>In the next steps we are going to wire up the user interface elements of the view we&#8217;ve created to the view controller we created earlier. First make sure <strong>File&#8217;s Owner</strong> is selected. In the menu bar, click on <strong>Tools</strong>, then <strong>Connections Inspector</strong>.</p>
<p>Under Outlets and Received Actions in the Connections Inspector make the following associations:</p>
<ul>
<li>Drag the &#8220;button&#8221; outlet to the button on the visual interface</li>
<li>Drag the &#8220;label&#8221; outlet to the label on the visual interface</li>
<li>Drag the &#8220;view&#8221; outlet to anywhere on the visual interface</li>
<li>Drag the &#8220;onButtonClick&#8221; action to the button on the visual interface. Select &#8220;Touch Up Inside&#8221;</li>
</ul>
<p style="text-align: center;"><img  title="012" src="http://gigapple.files.wordpress.com/2009/04/012.png?w=604" alt="012" class=" alignleft" /></p>
<p>At this point we&#8217;ve created our first sub-view, however we&#8217;re not going to be able to get to it from application just yet. That&#8217;s the next step.</p>
<p>Before moving on, go back into XCode and click on <strong>Build</strong> before moving onto the next part. Your build should compile and the results should report back successfully at this point.</p>
<h3>Navigating to a Sub-View from a UITableView</h3>
<p>The code below will do the following:</p>
<ul>
<li>Sets up an array of views and supplies that array to our UITable as a data source</li>
<li>Adds multiple sub views to our application using the sub view we&#8217;ve designed and written thus far</li>
<li>Allows us to navigate to different sub views upon view selection from our UITableView</li>
</ul>
<p>Open the file &#8220;RootViewController.h&#8221; and add the following code:</p>
<p><pre class="brush: csharp;">
#import &lt;UIKit/UIKit.h&gt;

@interface RootViewController : UITableViewController {
	IBOutlet NSMutableArray *views;
}

@property (nonatomic, retain) IBOutlet NSMutableArray *views;

@end
</pre></p>
<p>Open the file &#8220;RootViewController.m&#8221; and add the following code:</p>
<p><pre class="brush: csharp;">
#import "RootViewController.h"
#import "SubViewOneController.h"

@implementation RootViewController

@synthesize views;

- (void)awakeFromNib {
	// we'll keep track of our views in this array
	views = [ [NSMutableArray alloc] init];

	// allocate a set of views and add to our view array as a dictionary item
	SubViewOneController *subViewOneController = [[SubViewOneController alloc] init];
	subViewOneController.title = @"Subview One";
	[views addObject:[NSDictionary dictionaryWithObjectsAndKeys:
						@"Subview One",			@"title",
						subViewOneController,	@"controller",
						nil]];
	[subViewOneController release];

	subViewOneController = [[SubViewOneController alloc] init];
	subViewOneController.title = @"Subview Two";
	[views addObject:[NSDictionary dictionaryWithObjectsAndKeys:
					  @"Subview Two",			@"title",
					  subViewOneController,	@"controller",
					  nil]];
	[subViewOneController release];

	subViewOneController = [[SubViewOneController alloc] init];
	subViewOneController.title = @"Subview Three";
	[views addObject:[NSDictionary dictionaryWithObjectsAndKeys:
					  @"Subview Three",			@"title",
					  subViewOneController,	@"controller",
					  nil]];
	[subViewOneController release];

	// create a custom navigation bar button and set it to always say "Back"
	UIBarButtonItem *temporaryBarButtonItem = [[UIBarButtonItem alloc] init];
	temporaryBarButtonItem.title = @"Back";
	self.navigationItem.backBarButtonItem = temporaryBarButtonItem;
	[temporaryBarButtonItem release];

	//set the title of the main view
	self.title = @"Basic Navigation";
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

#pragma mark Table view methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [views count];
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }

    // Set up the cell...
	cell.text = [[views objectAtIndex:indexPath.row] objectForKey:@"title"];

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Navigation logic may go here. Create and push another view controller.
	UIViewController *targetViewController = [[views objectAtIndex: indexPath.row] objectForKey:@"controller"];
	[[self navigationController] pushViewController:targetViewController animated:YES];
}

- (void)dealloc {
	[views dealloc];
    [super dealloc];
}

@end
</pre></p>
<p>Click the &#8220;=<strong>Build and Go</strong> button in XCode. Our application thus far should now allow us to select a sub view and navigate to it. The application should look similar to the following:</p>
<p style="text-align: center;"><img  title="013" src="http://gigapple.files.wordpress.com/2009/04/013.png?w=290&h=558" alt="013" width="290" height="558" class=" alignleft" /></p>
<p style="text-align: center;"><img  title="014" src="http://gigapple.files.wordpress.com/2009/04/014.png?w=290&h=558" alt="014" width="290" height="558" class=" alignleft" /></p>
<h3>Accessing Global Application Data</h3>
<p>In an iPhone application, the Application Delegate can commonly be used to store global variables accessible by all views. You may run into a situation where a view may require data that has been modified by another view or may need to be notified of updates to this data. This piece of the tutorial will cover that very scenario. In this, we&#8217;ll be covering some key points in our code:</p>
<ul>
<li>Subscribing to central events</li>
<li>Broadcasting events globally</li>
<li>Reading/writing global application data</li>
</ul>
<p>To begin, let&#8217;s open the file <strong>BasicNavigationAppDelegate.h</strong> and add the following code.</p>
<p><pre class="brush: csharp;">
#import &lt;UIKit/UIKit.h&gt;

@interface BasicNavigationAppDelegate : NSObject &lt;UIApplicationDelegate&gt; {

	//Application Model Data
	NSString *modelData;

    UIWindow *window;
    UINavigationController *navigationController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;

- (void) setModelData:(NSString *)modelData;
- (NSString *) getModelData;

@end
</pre></p>
<p>Now open <strong>BasicNavigationAppDelegate.m</strong> and add the following code.</p>
<p><pre class="brush: csharp;">
#import "BasicNavigationAppDelegate.h"
#import "RootViewController.h"

@implementation BasicNavigationAppDelegate

@synthesize window;
@synthesize navigationController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
	// Configure and show the window
	[window addSubview:[navigationController view]];
	[window makeKeyAndVisible];
}

- (void)applicationWillTerminate:(UIApplication *)application {
	// Save data if appropriate
}

// accessor methods for "data" property

- (void) setModelData:(NSString *) newData {
	modelData = newData;
	[[NSNotificationCenter defaultCenter] postNotificationName:@"dataChangeEvent" object:self];
}

- (NSString *) getModelData {
	if ( modelData == nil ) {
		modelData = @"Hello World";
	}
	return modelData;
}

- (void)dealloc {
	[navigationController release];
	[window release];
	[super dealloc];
}

@end
</pre></p>
<p>We&#8217;ve added a model variable and accessor methods to read and write to this variable. Notice on the <code>setModelData</code> method, how we have the following line <code>[[NSNotificationCenter defaultCenter] postNotificationName:@"dataChangeEvent" object:self]</code>. When this setter method is called, we will be broadcasting an event, <code>dataChangeEvent</code>, to observers of this event notification. For this application, our sub views will subscribe to this event notification.</p>
<p>Go back and open up <strong>SubViewController.h</strong> and add the following line:</p>
<p><code>- (void) getModelData;</code></p>
<p>Now open <strong>SubViewOneController.m</strong>, and update the code to look like the following:</p>
<p><pre class="brush: csharp;">
#import "SubViewOneController.h"
#import "BasicNavigationAppDelegate.h"

@implementation SubViewOneController

@synthesize label, button;

- (id) init {
	self = [super init];
	if (self != nil)
	{
		// subscribe to changes on global data and course of action to take
		[[NSNotificationCenter defaultCenter]
		 addObserver:self
		 selector:@selector(onDataChangeEvent:)
		 name:@"dataChangeEvent"
		 object:nil];
	}
	return self;

}

- (IBAction) OnButtonClick:(id) sender {
	// this view will set our model data
	BasicNavigationAppDelegate *appDelegate =
	(BasicNavigationAppDelegate *)[[UIApplication sharedApplication] delegate];
	NSString *displayString = [NSString stringWithFormat: @"Set By %@", [self title]];
	[appDelegate setModelData:displayString];
}

- (void)onDataChangeEvent:(id) sender {
	[self getModelData];
}

-(void)viewWillAppear:(BOOL)animated {
	[self getModelData];
}

// set our label to reflect the latest copy of the data that we're observing
- (void) getModelData {
	BasicNavigationAppDelegate *appDelegate =
	(BasicNavigationAppDelegate *)[[UIApplication sharedApplication] delegate];
	[label setText:[appDelegate getModelData] ];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

- (void)dealloc {
    [super dealloc];
}

@end
</pre></p>
<p>Let&#8217;s note the relevant things that are going on here:</p>
<ul>
<li>The view subscribes to the <code>dataChangeEvent</code> on the <code>init</code> method. When the <code>dataChangeEvent</code> is fired, the method <code>onDataChangeEvent</code> is triggered and executed.</li>
<li>On Button click, we will be setting the the model data located in our application delegate. Remember, that in our implementation, whenever that variable is set, the <code>OnDataChangeEvent</code> is fired and all observers of that event will respond to it</li>
</ul>
<p>Here&#8217;s how we know that our sub views are operating off the same global data.</p>
<ul>
<li>Click on Sub View One, then click the button in that view. You&#8217;ll notice the label will change to &#8220;Set By Subview One&#8221;</li>
<li>Click &#8220;back&#8221;, then click on Sub View Two. Notice the label says &#8220;Set By Subview One&#8221;</li>
<li>Click the button, the label should change in Sub View Two to &#8220;Set By Subview Two&#8221;</li>
<li>Click &#8220;back, then click on Sub View Three. Notice the label says &#8220;Set By Subview Two&#8221;</li>
</ul>
<p>Do you notice what&#8217;s happening here? Our data is persisting across views and this data can be read and set by any of our sub views. What we&#8217;ve demonstrated here are some very basic practices in model-view-control design and implementation. I hope this lesson carries well for you. Happy coding.</p>
<p><strong>Related research and analysis from GigaOM Pro:</strong><br />Subscriber content. <a href="http://pro.gigaom.com/?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172588+iphone-dev-sessions-create-a-navigation-based-application&utm_content=leekuens">Sign up for a free trial</a>.</p><ul><li><a href="http://pro.gigaom.com/2011/11/connected-world-the-consumer-technology-revolution/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172588+iphone-dev-sessions-create-a-navigation-based-application&utm_content=leekuens">Connected world: the consumer technology&nbsp;revolution</a></li><li><a href="http://pro.gigaom.com/2012/04/survey-enterprise-mobility-perceptions-among-it-decision-makers/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172588+iphone-dev-sessions-create-a-navigation-based-application&utm_content=leekuens">Survey: the next wave of enterprise&nbsp;mobility</a></li><li><a href="http://pro.gigaom.com/2012/02/forecasting-the-tablet-market-over-366-million-units-by-2016/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172588+iphone-dev-sessions-create-a-navigation-based-application&utm_content=leekuens">Tablet market to hit over 377 million units by&nbsp;2016</a></li></ul><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=172588&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/iphone-dev-sessions-create-a-navigation-based-application/feed/</wfw:commentRss>
		<slash:comments>96</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a02edd843b0512456df0ace0b521f8ba?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">Keun</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/001.png" medium="image">
			<media:title type="html">001</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/002.png" medium="image">
			<media:title type="html">002</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/003.png" medium="image">
			<media:title type="html">003</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/004.png" medium="image">
			<media:title type="html">004</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/005.png" medium="image">
			<media:title type="html">005</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/006.png" medium="image">
			<media:title type="html">006</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/007.png" medium="image">
			<media:title type="html">007</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/008.png" medium="image">
			<media:title type="html">008</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/009.png" medium="image">
			<media:title type="html">009</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/010.png" medium="image">
			<media:title type="html">010</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/011.png" medium="image">
			<media:title type="html">011</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/012.png" medium="image">
			<media:title type="html">012</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/013.png" medium="image">
			<media:title type="html">013</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/014.png" medium="image">
			<media:title type="html">014</media:title>
		</media:content>
	</item>
		<item>
		<title>iPhone Dev Sessions: How To Make An Orientation-Aware Clock</title>
		<link>http://gigaom.com/apple/iphone-dev-sessions-how-to-make-an-orientation-aware-clock/</link>
		<comments>http://gigaom.com/apple/iphone-dev-sessions-how-to-make-an-orientation-aware-clock/#comments</comments>
		<pubDate>Wed, 08 Apr 2009 17:00:19 +0000</pubDate>
		<dc:creator>Henry Balanon</dc:creator>
				<category><![CDATA[SYN Feature Enterprise]]></category>
		<category><![CDATA[Walkthroughs]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iphone dev sessions]]></category>

		<guid isPermaLink="false">http://theappleblog.com/?p=20939</guid>
		<description><![CDATA[For this tutorial we&#8217;re going to build a simple clock that is orientation-aware, meaning that when you rotate your iPhone, the time rotates with it. I&#8217;m assuming you have a basic knowledge of the iPhone SDK. To get started, you will need a label for the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=172581&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><img  title="iphone_clock" src="http://gigapple.files.wordpress.com/2009/04/iphone_clock.png?w=570&h=296" alt="iphone_clock" width="570" height="296" class=" alignleft" /></p>
<p class="excerpt">For this tutorial we&#8217;re going to build a simple clock that is orientation-aware, meaning that when you rotate your iPhone, the time rotates with it. I&#8217;m assuming you have a basic knowledge of the <a title="iPhone Dev Center - Apple Developer Connection" href="http://developer.apple.com/iphone/">iPhone SDK</a>.</p>
<p>To get started, you will need a label for the time and a background image. You will also need a timer. To get started, you must declare your outlets in code before Interface Builder will be able to use them. I&#8217;ll show you how to do that now.</p>
<h3>Let&#8217;s Get Our Hands in Some Code</h3>
<p>Edit <em><strong>SimpleClockViewController.h</strong></em> so it looks like this:</p>
<p><pre class="brush: csharp;">

#import &lt;UIKit/UIKit.h&gt;

@interface SimpleClockViewController : UIViewController {
	IBOutlet UILabel* clockLabel;
	NSTimer *myTicker;
}

@end

</pre></p>
<p>The <code>myTicker</code> is going to be responsible for updating the <code>clockLabel</code>. We will implement that code later. <span id="more-172581"></span></p>
<p>The next thing you want to do is drag <code>background_image.png</code> to your project (see image below). You can get the image <a href="http://gigapple.files.wordpress.com/2009/04/background_image.png">here</a>.</p>
<p><img  title="image-510" src="http://gigapple.files.wordpress.com/2009/04/image-510.png?w=510&h=248" alt="image-510" width="510" height="248" class=" alignleft" /></p>
<p>You want to copy the item to the project&#8217;s directory so put a check mark next to &#8220;Copy items into destination group&#8217;s folder (if needed).&#8221; Your settings should look similar to this. Click Add.</p>
<p><img  title="2009-03-09_1229" src="http://gigapple.files.wordpress.com/2009/04/2009-03-09_1229.png?w=400&h=374" alt="2009-03-09_1229" width="400" height="374" class=" alignleft" /></p>
<p>Open <em><strong>SimpleClockViewController.xib</strong></em>. Drag <code>UIImageView</code> from the Library to the View window. This will act as a placement holder for our background image.</p>
<p><img  title="image-5101" src="http://gigapple.files.wordpress.com/2009/04/image-5101.png?w=510&h=415" alt="image-5101" width="510" height="415" class=" alignleft" /></p>
<p>Bring up the Attributes Inspector. Set the Image to <code>background_image.png</code>. Set the Mode to <strong>Scale To Fill</strong> so that the <code>background_image.png</code> stretches out when we rotate the iPhone.</p>
<p><img  title="2009-03-06_15431" src="http://gigapple.files.wordpress.com/2009/04/2009-03-06_15431.png?w=287&h=339" alt="2009-03-06_15431" width="287" height="339" class=" alignleft" /></p>
<p>Bring up the Size Inspector and change the Autosizing settings to look like this. The arrows in the Autosizing box act as outward springs, which cause the view to resize itself proportionally based on the width or height of its superview. The &#8220;I&#8221;s act as struts that keep a fixed distance when the View is changed when you rotate the iPhone. If that&#8217;s hard to visualize, Interface Builder has an animation to the right of the Autosizing box will help you visualize its current settings.</p>
<p><img  title="2009-03-06_1545" src="http://gigapple.files.wordpress.com/2009/04/2009-03-06_1545.png?w=287&h=465" alt="2009-03-06_1545" width="287" height="465" class=" alignleft" /></p>
<p>Drag a Label to the View window and resize to approximately the width of the window. Center it. This makes the time larger and also positions the time to be rotated around its center point when you turn the iPhone into landscape mode.</p>
<p><img  title="image-5102" src="http://gigapple.files.wordpress.com/2009/04/image-5102.png?w=510&h=381" alt="image-5102" width="510" height="381" class=" alignleft" /></p>
<p>Change the font of the label by selecting the Label and hitting Command-T. Change the settings so you&#8217;re using Helvetica, Bold, size 48.</p>
<p><img  title="2009-03-06_15561" src="http://gigapple.files.wordpress.com/2009/04/2009-03-06_15561.png?w=445&h=270" alt="2009-03-06_15561" width="445" height="270" class=" alignleft" /></p>
<p>Bring up the Attributes Inspector. Change the Layout Alignment to Center. Again, we&#8217;re doing this so the time rotates around its center.  Change the font color to white so it looks good on the dark background. It should look similar to this:</p>
<p><img  title="2009-03-06_1557" src="http://gigapple.files.wordpress.com/2009/04/2009-03-06_1557.png?w=287&h=663" alt="2009-03-06_1557" width="287" height="663" class=" alignleft" /></p>
<p>Bring up the Size Inspector and change your Autosizing settings to look like the image below. This makes sure the time rotates and positions itself correctly around its center.</p>
<p><img  title="2009-03-06_1557a" src="http://gigapple.files.wordpress.com/2009/04/2009-03-06_1557a.png?w=287&h=663" alt="2009-03-06_1557a" width="287" height="663" class=" alignleft" /></p>
<p>Lastly, Control-Drag from File&#8217;s Owner to the Label and choose <code>clockLabel</code> when the outlet box pops up. This tells your Label which variable it is in the code.</p>
<p><img  title="2009-03-09_1311" src="http://gigapple.files.wordpress.com/2009/04/2009-03-09_1311.png?w=434&h=240" alt="2009-03-09_1311" width="434" height="240" class=" alignleft" /></p>
<p>Save and close Interface Builder. Back in Xcode, open <em><strong>SimpleClockViewController.h</strong></em> and add <code>runTimer</code> and <code>showActivity</code> methods. These declare the functions we&#8217;re going to write.</p>
<p><pre class="brush: csharp;">

#import &lt;UIKit/UIKit.h&gt;

@interface SimpleClockViewController : UIViewController {
	IBOutlet UILabel* clockLabel;
	NSTimer *myTicker;
}

/* New Methods */
- (void) runTimer;
- (void)showActivity;

</pre></p>
<p>Open <em><strong>SimpleClockViewController.m</strong></em> and add the methods we just declared.</p>
<p><pre class="brush: csharp;">

- (void)runTimer {
  // This starts the timer which fires the showActivity
  // method every 0.5 seconds
  myTicker = [NSTimer scheduledTimerWithTimeInterval: 0.5
                        target: self
                        selector: @selector(showActivity)
                        userInfo: nil
                         repeats: YES];

}

// This method is run every 0.5 seconds by the timer created
// in the function runTimer
- (void)showActivity {

  NSDateFormatter *formatter =
          [[[NSDateFormatter alloc] init] autorelease];
    NSDate *date = [NSDate date];

    // This will produce a time that looks like &quot;12:15:00 PM&quot;.
    [formatter setTimeStyle:NSDateFormatterMediumStyle];

  // This sets the label with the updated time.
  [clockLabel setText:[formatter stringFromDate:date]];

}

</pre></p>
<p>The <code>runTimer</code> method only has 1 line of code split into multiple lines. All it does is call the <code>showActivity</code> method every 0.5 seconds.</p>
<p>The <code>showActivity</code> method formats the <code>clockLabel</code> so it looks like &#8220;12:15:00 PM&#8221; and sets it to the current time. As mentioned above, this method is called every 0.5 seconds.</p>
<p>We want to call <code>runTimer</code> after the view loads. This is a common method that, when Xcode generated <em><strong>SimpleClockViewController.m</strong></em>, they included a method called <code>viewDidLoad</code>. This method is called immediately after the View items are loaded. Find the <code>viewDidLoad</code> method and uncomment it.</p>
<p>Add <code>[self runTimer];</code> to the end of the method. It should now look like this:</p>
<p><pre class="brush: csharp;">

// Implement viewDidLoad to do additional
// setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

// This calls the runTimer method after loading
// SimpleClockViewController.xib
  [self runTimer];
}

</pre></p>
<p>When Xcode generated <em><strong>SimpleClockViewController.m</strong></em>, they also included <code>shouldAutorotateToInterfaceOrientation</code>. By default, views display only in portrait orientation, so you need to implement <code>shouldAutorotateToInterfaceOrientation</code> method if you want to support other orientations.</p>
<p>Locate the <code>shouldAutorotateToInterfaceOrientation</code> method and uncomment it. You can support only <em>some</em> orientations such as portrait or landscape with Home button on the right, but we don&#8217;t need to limit ourselves to those scenarios. We want to support <strong>all</strong> orientations so the view rotates correctly no matter how we&#8217;re holding the iPhone. To do this, replace <code>return (interfaceOrientation == UIInterfaceOrientationPortrait);</code> with <code>return YES;</code>.</p>
<p><pre class="brush: csharp;">

// Override to allow orientations other than
// the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return YES;
}

</pre></p>
<p>Now you can build and run it! Hit Command-Left to see your UI rotate with the iPhone simulator. You can Build and Run the project to make sure everything is compiling and running.</p>
<p><strong>Related research and analysis from GigaOM Pro:</strong><br />Subscriber content. <a href="http://pro.gigaom.com/?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172581+iphone-dev-sessions-how-to-make-an-orientation-aware-clock&utm_content=balanon">Sign up for a free trial</a>.</p><ul><li><a href="http://pro.gigaom.com/2011/01/mobile-q4-all-eyes-were-on-android-4g-and-the-rising-tablet-tide/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172581+iphone-dev-sessions-how-to-make-an-orientation-aware-clock&utm_content=balanon">Mobile Q4: All Eyes Were on Android, 4G and the Rising Tablet&nbsp;Tide</a></li><li><a href="http://pro.gigaom.com/2010/12/report-a-mobile-video-market-overview/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172581+iphone-dev-sessions-how-to-make-an-orientation-aware-clock&utm_content=balanon">Report: A Mobile Video Market&nbsp;Overview</a></li><li><a href="http://pro.gigaom.com/2010/10/in-q3-the-tablet-and-4g-were-the-big-stories/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=172581+iphone-dev-sessions-how-to-make-an-orientation-aware-clock&utm_content=balanon">In Q3, the Tablet and 4G Were the Big&nbsp;Stories</a></li></ul><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=172581&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/iphone-dev-sessions-how-to-make-an-orientation-aware-clock/feed/</wfw:commentRss>
		<slash:comments>57</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/e0c66e7aa8ea6f9b5fdd72fb70545d4c?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">balanon</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/iphone_clock.png?w=570" medium="image">
			<media:title type="html">iphone_clock</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/image-510.png" medium="image">
			<media:title type="html">image-510</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/2009-03-09_1229.png" medium="image">
			<media:title type="html">2009-03-09_1229</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/image-5101.png" medium="image">
			<media:title type="html">image-5101</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/2009-03-06_15431.png" medium="image">
			<media:title type="html">2009-03-06_15431</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/2009-03-06_1545.png" medium="image">
			<media:title type="html">2009-03-06_1545</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/image-5102.png" medium="image">
			<media:title type="html">image-5102</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/2009-03-06_15561.png" medium="image">
			<media:title type="html">2009-03-06_15561</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/2009-03-06_1557.png" medium="image">
			<media:title type="html">2009-03-06_1557</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/2009-03-06_1557a.png" medium="image">
			<media:title type="html">2009-03-06_1557a</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2009/04/2009-03-09_1311.png" medium="image">
			<media:title type="html">2009-03-09_1311</media:title>
		</media:content>
	</item>
		<item>
		<title>iPhone SDK Tutorial: Build a Simple RSS reader for the iPhone</title>
		<link>http://gigaom.com/apple/tutorial-build-a-simple-rss-reader-for-iphone/</link>
		<comments>http://gigaom.com/apple/tutorial-build-a-simple-rss-reader-for-iphone/#comments</comments>
		<pubDate>Mon, 04 Aug 2008 17:10:24 +0000</pubDate>
		<dc:creator>Jason Terhorst</dc:creator>
				<category><![CDATA[Walkthroughs]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[iphone dev sessions]]></category>
		<category><![CDATA[RSS]]></category>
		<category><![CDATA[sdk]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://theappleblog.com/?p=3900</guid>
		<description><![CDATA[With this I&#8217;m assuming you have a bit of familiarity with the iPhone SDK &#8211; you can download it for free from Apple&#8217;s site, and follow along here. We&#8217;re going to build an RSS feed reader for a simple feed (from The Apple Blog, no less). [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=171576&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p class="excerpt">With this I&#8217;m assuming you have a bit of familiarity with the iPhone SDK &#8211; you can <a href="http://developer.apple.com/iphone/">download it for free</a> from Apple&#8217;s site, and follow along here. We&#8217;re going to build an RSS feed reader for a simple feed (from The Apple Blog, no less).</p>
<p><img src="http://gigapple.files.wordpress.com/2008/07/picture-26.png?w=604" alt="" class=" alignleft" /></p>
<h3>Let&#8217;s get started</h3>
<ol>
<li>Open Xcode and choose the &#8220;File&#8221; menu, in which you&#8217;ll click the &#8220;New Project&#8230;&#8221; item.</li>
<li>Click &#8220;Application&#8221; under &#8220;iPhone OS&#8221; in the list at left.</li>
<li>On the right, choose &#8220;Navigation-Based Application&#8221;. Then click the &#8220;Choose&#8230;&#8221; button. You&#8217;ll be prompted to pick a name and location. Type in the name &#8220;TAB RSS reader&#8221;.</li>
<li>Save it wherever you wish.</li>
</ol>
<p>The Xcode project window will appear, with the standard 3 panes &#8211; I recommend pulling the horizontal divider on the right side all the way to the top, since you&#8217;ll need that editor area and all the real estate you can give it.<br />
<span id="more-171576"></span><br />
Do you see a &#8220;Build and Go&#8221; button in the toolbar? Click it, or go to the &#8220;Build&#8221; menu, and click &#8220;Build and Go (Run)&#8221; there. It should open the Simulator application and launch a simple iPhone app that displays a blank navigation bar and blank table. Whee! Your first iPhone app. Now let&#8217;s sculpt it into something.</p>
<p><img  title="iphone-xcode-tutorial-28.png" src="http://gigapple.files.wordpress.com/2008/07/iphone-xcode-tutorial-28.png?w=247&h=161" alt="" width="247" height="161" class=" alignleft" /> The project template that Apple provides has a lot of things already set up to get us started. On the list at the left of the project window, find &#8220;MainWindow.xib&#8221;, and double-click it. This is the basic framing of your application&#8217;s UI. Be careful not to mess around here too much. You just need to do one thing: you should see a &#8220;Navigation Controller&#8221; window with a basic interface mocked up &#8211; double-click on the navigation bar (which has no title in it), and type &#8220;The Apple Blog&#8221;. Press return. Save and quit Interface Builder.</p>
<p>Click once on &#8220;RootViewController.h&#8221; in the list, and see the code on the right. Make it look like this:</p>
<pre class="scroll"><code>
@interface RootViewController : UITableViewController {
	IBOutlet UITableView * newsTable;
	UIActivityIndicatorView * activityIndicator;
	CGSize cellSize;
	NSXMLParser * rssParser;
	NSMutableArray * stories;

	// a temporary item; added to the "stories" array one at a time, and cleared for the next one
	NSMutableDictionary * item;

	// it parses through the document, from top to bottom...
	// we collect and cache each sub-element value, and then save each item to our array.
	// we use these to track each current item, until it's ready to be added to the "stories" array
	NSString * currentElement;
	NSMutableString * currentTitle, * currentDate, * currentSummary, * currentLink;
}
@end
</code></pre>
<p>That&#8217;s the declaration file, where we&#8217;re telling the compiler what to expect when it runs through the controller logic. Here&#8217;s where the real work happens&#8230; Open &#8220;<code>RootViewController.m</code>&#8220;.</p>
<p>You&#8217;ll see that there&#8217;s more of the basic code to make that table view display &#8211; this controller is the table&#8217;s &#8220;delegate&#8221; &#8211; the table looks here to find out what it&#8217;s supposed to see/display/do in various situations, and sends calls for methods when the user performs various actions.</p>
<p>Change the value of <code>- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section</code> to <code>return [stories count];</code></p>
<p>In our declarations, we told it we would have an array (<em>NSMutableArray</em> &#8211; a modifiable collection of objects), which we called &#8220;stories&#8221;. The [brackets] around that bit signify that it&#8217;s a message &#8211; we&#8217;re asking the <strong>stories</strong> array what its current <em>count</em> is &#8211; that is, how many items it has. Our RSS reader will grab as many items as it can (one for each story in the RSS feed), and place them in that array, so this method will tell the table <em>This is how many rows we need: one for each item in the array, or for each item in the feed</em>. Before, it was set to 0, so you&#8217;re giving it more information on our array.</p>
<p>Next up, modify the method below the one you just changed, like so:</p>
<pre class="scroll"><code>
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	static NSString *MyIdentifier = @"MyIdentifier";
	UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

	if (cell == nil) {
		cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
	}

	// Set up the cell
	int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
	[cell setText:[[stories objectAtIndex: storyIndex] objectForKey: @"title"]];

	return cell;
}
</code></pre>
<p>As you can see, we used the &#8220;<code>setText:</code>&#8221; method to tell the cell what the contents will be. Each row in the table is basically a cell, and its properties are set in this method.</p>
<p>There are 4 methods highlighted in green about 3/4 of the way down &#8211; you can delete those if you wish, since we won&#8217;t be using them. They have to do with adding/deleting items.</p>
<p>If you were to run the program again now, it still wouldn&#8217;t do anything: we haven&#8217;t added the ability to download the feed and use it yet, so let&#8217;s do that now.</p>
<p>Edit the &#8220;<code>viewDidAppear:</code>&#8221; method to look like this:</p>
<pre class="scroll"><code>
- (void)viewDidAppear:(BOOL)animated {
	[super viewDidAppear:animated];

	if ([stories count] == 0) {
		NSString * path = @"http://feeds.feedburner.com/TheAppleBlog";
		[self parseXMLFileAtURL:path];
	}

	cellSize = CGSizeMake([newsTable bounds].size.width, 60);
}
</code></pre>
<p>This is where we tell the parser which feed to download. It calls a method, which you&#8217;ll want to paste in now:</p>
<pre class="scroll"><code>
- (void)parseXMLFileAtURL:(NSString *)URL {
	stories = [[NSMutableArray alloc] init];

	//you must then convert the path to a proper NSURL or it won't work
	NSURL *xmlURL = [NSURL URLWithString:URL];

	// here, for some reason you have to use NSClassFromString when trying to alloc NSXMLParser, otherwise you will get an object not found error
	// this may be necessary only for the toolchain
	rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];

	// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
	[rssParser setDelegate:self];

	// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
	[rssParser setShouldProcessNamespaces:NO];
	[rssParser setShouldReportNamespacePrefixes:NO];
	[rssParser setShouldResolveExternalEntities:NO];

	[rssParser parse];
}
</code></pre>
<p>This is a method we&#8217;ve added that creates the empty array for stories, creates a parser, and starts downloading the feed. As the parser works, this controller we&#8217;re working in will receive the various delegate methods, which you can paste in now:</p>
<pre class="scroll"><code>
- (void)parserDidStartDocument:(NSXMLParser *)parser {
	NSLog(@"found file and started parsing");
}

- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
	NSString * errorString = [NSString stringWithFormat:@"Unable to download story feed from web site (Error code %i )", [parseError code]];
	NSLog(@"error parsing XML: %@", errorString);

	UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:@"Error loading content" message:errorString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
	[errorAlert show];
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
	//NSLog(@"found this element: %@", elementName);
	currentElement = [elementName copy];

	if ([elementName isEqualToString:@"item"]) {
		// clear out our story item caches...
		item = [[NSMutableDictionary alloc] init];
		currentTitle = [[NSMutableString alloc] init];
		currentDate = [[NSMutableString alloc] init];
		currentSummary = [[NSMutableString alloc] init];
		currentLink = [[NSMutableString alloc] init];
	}
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{

	//NSLog(@"ended element: %@", elementName);
	if ([elementName isEqualToString:@"item"]) {
		// save values to an item, then store that item into the array...
		[item setObject:currentTitle forKey:@"title"];
		[item setObject:currentLink forKey:@"link"];
		[item setObject:currentSummary forKey:@"summary"];
		[item setObject:currentDate forKey:@"date"];

		[stories addObject:[item copy]];
		NSLog(@"adding story: %@", currentTitle);
	}
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
	//NSLog(@"found characters: %@", string);
	// save the characters for the current item...
	if ([currentElement isEqualToString:@"title"]) {
		[currentTitle appendString:string];
	} else if ([currentElement isEqualToString:@"link"]) {
		[currentLink appendString:string];
	} else if ([currentElement isEqualToString:@"description"]) {
		[currentSummary appendString:string];
	} else if ([currentElement isEqualToString:@"pubDate"]) {
		[currentDate appendString:string];
	}
}

- (void)parserDidEndDocument:(NSXMLParser *)parser {

	[activityIndicator stopAnimating];
	[activityIndicator removeFromSuperview];

	NSLog(@"all done!");
	NSLog(@"stories array has %d items", [stories count]);
	[newsTable reloadData];
}
</code></pre>
<p>Unfortunately, the NSXMLParser is the only simple XML-parsing tool available on iPhone (some of my favorites from the Mac are missing). So, this means we have to crunch through the file in order from top to bottom. We have a series of strings that we assign values to, and then collect them into story items, which are saved one by one. Once it hits the closing &#8220;item&#8221; tag, it saves that story, clears out the fields, and starts on the next item until we reach the end of the file. Not my favorite approach, but it works.</p>
<h3>Finishing up</h3>
<p>We need to shut off any potential memory leaks (it&#8217;s a good habit to get into, when you don&#8217;t have garbage collection &#8211; who needs that anyway?). Drop in this change:</p>
<pre class="scroll"><code>
- (void)dealloc {
	[currentElement release];
	[rssParser release];
	[stories release];
	[item release];
	[currentTitle release];
	[currentDate release];
	[currentSummary release];
	[currentLink release];

	[super dealloc];
}
</code></pre>
<p><img src="http://gigapple.files.wordpress.com/2008/07/iphone-xcode-tutorial-30.png?w=604" alt="" class=" alignleft" /></p>
<p>Next, open up &#8220;<code>RootViewController.xib</code>&#8220;, and hold down the &#8220;control&#8221; key on your keyboard, while dragging from the &#8220;RootViewController&#8221; cube icon over to the table view, and release. You should see a list of three items appear, so click on the &#8220;<code>newsTable</code>&#8221; item. Save and quit Interface Builder.</p>
<h3>Build and Go</h3>
<p><img src="http://gigapple.files.wordpress.com/2008/07/iphone-xcode-tutorial-31.png?w=196&h=213" alt="" width="196" height="213" class=" alignleft" /></p>
<p>If you click &#8220;Build and Go&#8221;, you&#8217;ll see the results we have so far. If you were to run this on an actual iPhone and not in simulator, the results would be different slightly: the hardware is slower, and if you&#8217;re on EDGE, the RSS feed will take a very long time to download. But, hey, it works! One thing that doesn&#8217;t work yet: when you tap on an item in the table, nothing happens. This is default behavior, but let&#8217;s make the stories open in Safari &#8211; that&#8217;s an easy thing to do. Just change this method:</p>
<pre class="scroll"><code>
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	// Navigation logic

	int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];

	NSString * storyLink = [[stories objectAtIndex: storyIndex] objectForKey: @"link"];

	// clean up the link - get rid of spaces, returns, and tabs...
	storyLink = [storyLink stringByReplacingOccurrencesOfString:@" " withString:@""];
	storyLink = [storyLink stringByReplacingOccurrencesOfString:@"n" withString:@""];
	storyLink = [storyLink stringByReplacingOccurrencesOfString:@"	" withString:@""];

	NSLog(@"link: %@", storyLink);
	// open in Safari
	[[UIApplication sharedApplication] openURL:[NSURL URLWithString:storyLink]];
}
</code></pre>
<p>Now, click &#8220;Build and Go&#8221; again, to see that it works.</p>
<h3>Done for Now</h3>
<p><a href="http://media.theappleblog.com/downloads/TAB_RSS_reader.zip"><img style="margin: 5px;" src="http://gigapple.files.wordpress.com/2008/07/iphone-xcode-tutorial-3.png?w=200&h=86" alt="" width="200" height="86" class=" alignleft" /></a><br />
<em>You can download the finished project file here if you wish</em>.</p>
<p>Check back here later, and we&#8217;ll cover some steps on how to clean up the UI, and add some navigation.</p>
<p><strong>Related research and analysis from GigaOM Pro:</strong><br />Subscriber content. <a href="http://pro.gigaom.com/?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=171576+tutorial-build-a-simple-rss-reader-for-iphone&utm_content=gigaguest">Sign up for a free trial</a>.</p><ul><li><a href="http://pro.gigaom.com/2011/07/mobile-q2-smartphone-growth-surges-ipads-rule-continues/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=171576+tutorial-build-a-simple-rss-reader-for-iphone&utm_content=gigaguest">Mobile Q2: Smartphone growth surges; iPad&#8217;s rule&nbsp;continues</a></li><li><a href="http://pro.gigaom.com/2010/09/how-to-market-your-iphone-app-a-developers-guide/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=171576+tutorial-build-a-simple-rss-reader-for-iphone&utm_content=gigaguest">How to Market Your iPhone App: A Developer&#8217;s&nbsp;Guide</a></li><li><a href="http://pro.gigaom.com/2012/04/connected-consumer-q1-controversy-courtrooms-and-the-cloud/?utm_source=apple&amp;utm_medium=editorial&amp;utm_campaign=waterfall?utm_source=apple&utm_medium=editorial&utm_campaign=auto3&utm_term=171576+tutorial-build-a-simple-rss-reader-for-iphone&utm_content=gigaguest">Controversy, courtrooms and the cloud in&nbsp;Q1</a></li></ul><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=gigaom.com&#038;blog=14960843&#038;post=171576&#038;subd=gigaom2&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://gigaom.com/apple/tutorial-build-a-simple-rss-reader-for-iphone/feed/</wfw:commentRss>
		<slash:comments>259</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4411542bbd7a2a9a2fc2a1b38809e45c?s=96&#38;d=retro&#38;r=PG" medium="image">
			<media:title type="html">gigaguest</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2008/07/picture-26.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2008/07/iphone-xcode-tutorial-28.png" medium="image">
			<media:title type="html">iphone-xcode-tutorial-28.png</media:title>
		</media:content>

		<media:content url="http://gigapple.files.wordpress.com/2008/07/iphone-xcode-tutorial-30.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2008/07/iphone-xcode-tutorial-31.png" medium="image" />

		<media:content url="http://gigapple.files.wordpress.com/2008/07/iphone-xcode-tutorial-3.png" medium="image" />
	</item>
	</channel>
</rss>
