<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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:series="http://unfoldingneurons.com/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"> <channel><title>Mobiletuts+</title> <link>http://mobile.tutsplus.com</link> <description>iPhone, Android, Windows and BlackBerry mobile development tutorials.</description> <lastBuildDate>Thu, 23 May 2013 15:04:50 +0000</lastBuildDate> <language /> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.5</generator> <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/MobileTuts" /><feedburner:info uri="mobiletuts" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>MobileTuts</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><title>iOS SDK: Advanced UIImage Techniques</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/wPO8XSmQptY/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-advanced-uiimage-techniques/#comments</comments> <pubDate>Thu, 23 May 2013 15:04:50 +0000</pubDate> <dc:creator>Akiel Khan</dc:creator> <category><![CDATA[iOS SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17207</guid> <description>&lt;p&gt;In this tutorial, we&amp;#8217;ll look at some of the advanced features and usage patterns of the humble &lt;code&gt;UIImage&lt;/code&gt; class in iOS. By the end of this tutorial, you will have learned the following: how to make images in code, how to create resizable images for UI elements like callouts, and how to create animated images.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;Theoretical Overview&lt;/h2&gt;&lt;p&gt;If you&amp;#8217;ve ever had to display an image in your iOS app, you&amp;#8217;re probably familiar with &lt;code&gt;UIImage&lt;/code&gt;. It&amp;#8217;s the class that allows you to represent images on iOS. This is by far the most common way of using &lt;code&gt;UIImage&lt;/code&gt; and is quite straightforward: you have an image file in one of several standard image formats (PNG, JPEG, BMP, etc.) and you wish to display it in your app&amp;#8217;s interface. You instantiate a new &lt;code&gt;UIImage&lt;/code&gt; instance by sending the class message &lt;code&gt;imageNamed:&lt;/code&gt;.  If you have an instance of &lt;code&gt;UIImageView&lt;/code&gt;, you can set its &lt;code&gt;image&lt;/code&gt; property to the &lt;code&gt;UIImage&lt;/code&gt; instance, and then you can stick in the image view into your interface by setting it as a subview to your onscreen view:&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
 UIImage *img = [UIImage imageNamed:filename];
 UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
 // Set frame, etc. ...
 [self.view addSubview:imgView];
 &lt;/pre&gt;&lt;p&gt;You can also carry out the equivalent of the above procedure directly in Interface Builder.&lt;/p&gt;&lt;p&gt;There are some other ways of instantiating an image, such as from a URL, or from an archived image that was stored as an &lt;code&gt;NSData&lt;/code&gt; type, but we won&amp;#8217;t focus on those aspects in this tutorial.&lt;/p&gt;&lt;p&gt;Before we talk about creating images in code, recall that at the most primitive level, we know what a 2D image really is: a two-dimensional array of pixel values. The region of memory representing the pixel array for an image is often referred to as its &lt;em&gt;bitmap store&lt;/em&gt;. This is sometimes useful to keep in mind when making memory considerations.  However, it is important to realize that a &lt;code&gt;UIImage&lt;/code&gt; is really a higher level abstraction of an image than that of a pixel array, and one that has been optimized according to the demands and usage scenarios of a mobile platform.  While it is theoretically possible to create an image by populating an entire pixel array with values, or to reach into an existing image&amp;#8217;s bitmap and read or modify the value of an individual pixel, it is rather inconvenient to do so on iOS and is not really facilitated by the API. However since the majority of app developers seldom find real need to mess with images at the pixel level, it&amp;#8217;s usually not an issue.&lt;/p&gt;&lt;p&gt;What &lt;code&gt;UIImage&lt;/code&gt; (or more generally, &lt;em&gt;UIKit&lt;/em&gt; and &lt;em&gt;Core Graphics&lt;/em&gt;) does facilitate the developer to do is to create a new image by compositing existing images in interesting ways, or to generate an image by rasterizing  a vector drawing constructed using &lt;em&gt;UIKit&lt;/em&gt;&amp;#8216;s &lt;code&gt;UIBezierPath&lt;/code&gt; class (or Core graphic&amp;#8217;s &lt;code&gt;CGPath...&lt;/code&gt; functions). If you want to write an app that lets the user create a collage of their pictures, it&amp;#8217;s easy to do with &lt;em&gt;UIKit&lt;/em&gt; and &lt;code&gt;UIImage&lt;/code&gt;. If you&amp;#8217;ve developed, say, a freehand drawing app and you want to let the user save his creation, then the simplest approach would involve extracting a &lt;code&gt;UIImage&lt;/code&gt; from the drawing context. In the first section of this tutorial, you&amp;#8217;ll learn exactly how both of these ideas can be accomplished!&lt;/p&gt;&lt;p&gt;It is important to keep in mind that a &lt;code&gt;UIImage&lt;/code&gt; constructed this way is no different than an image obtained by opening a picture from the photo album, or downloading from the Internet: it can be saved to the archive or uploaded to the photo album or displayed in a &lt;code&gt;UIImageView&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Image resizing&lt;/em&gt; is an important type of image manipulation. Obviously you&amp;#8217;d like to avoid enlarging an image, because that causes the image&amp;#8217;s quality and sharpness to suffer. However, there are certain scenarios in which resizable images are needed and there actually are sensible ways to do so that don&amp;#8217;t degrade the quality of the image. &lt;code&gt;UIImage&lt;/code&gt; caters for this situation by permitting images that have an inner resizable area and &amp;#8220;edge insets&amp;#8221; on the image borders that resize in a particular direction, or don&amp;#8217;t resize at all. Furthermore, the resizing can be carried out either by tiling or stretching the resizable portions for two somewhat different effects that can be useful in different situations.&lt;/p&gt;&lt;p&gt;The second part section of the implementation will show a concrete implementation of this idea. We&amp;#8217;ll write a nifty little class that can display any amount of text inside a resizable image!&lt;/p&gt;&lt;p&gt;Finally, we&amp;#8217;ll talk a bit about animating images with &lt;code&gt;UIImage&lt;/code&gt;. As you can probably guess, this means &amp;#8220;playing&amp;#8221; a series of images in succession, giving rise to the illusion of animation (much like the animated GIFs that you see on the Internet). While this might seem a bit limited, in simple situations &lt;code&gt;UIImage&lt;/code&gt;&amp;#8216;s animated image support might be just what you need, and all it takes is a couple of lines of code to get up and running. That&amp;#8217;s what we&amp;#8217;ll look at in the third and final section of this tutorial! Time to roll up our sleeves and get to work!&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Starting a New Project&lt;/h2&gt;&lt;p&gt;Create a new iOS project in Xcode, with the &amp;#8220;Empty Application&amp;#8221; template. Call it &lt;strong&gt;&amp;#8220;UIImageFun&amp;#8221;&lt;/strong&gt;. Check the option for Automatic Reference Counting, but uncheck the options for Core Data and Unit Tests.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_1.png" alt="Creating a new Xcode project" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;figcaption&gt;Creating a new Xcode project&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;A small note, before we proceed: this tutorial uses several sets of images, and to obtain these you&amp;#8217;ll need to click where it says &amp;#8220;Download Source Files&amp;#8221; at the top of this page. After downloading and unzipping the archive, drag the folder named &amp;#8220;Images&amp;#8221; into the Project Navigator &amp;#8211; the leftmost tab in the lefthand pane in Xcode. If the left pane isn&amp;#8217;t visible, then press the key combination &lt;strong&gt;⌘ + 0&lt;/strong&gt; to make it visible and ensure the leftmost tab &amp;#8211; whose icon looks like a folder &amp;#8211; is selected.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_2.png" alt="Drag and drop the Images folder into your project" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;figcaption&gt;Drag and drop the Images folder into your project&lt;/figcaption&gt; &lt;/figure&gt; Ensure that the &amp;#8220;&lt;em&gt;Copy items into destination group&amp;#8217;s folder (if needed)&lt;/em&gt;&amp;#8221; option in the dialog box is checked&amp;#8221;. &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_3.png" alt="Ensure that the files get copied to your project folder" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;figcaption&gt;Ensure that the files get copied to your project folder&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;The downloaded file also contains the complete Xcode project with the images already added to the project, in case you get stuck somewhere.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Creating an Image in Code&lt;/h2&gt;&lt;p&gt;Create a new file for an Objective-C class, call it &lt;code&gt;ViewController&lt;/code&gt; and make it a subclass of &lt;code&gt;UIViewController&lt;/code&gt;. Ensure that the options related to iPad and XIB are left unchecked.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_4.png" alt="Make a new view controller" /&gt;&lt;/p&gt; &lt;figcaption&gt;Make a new view controller&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;Replace all the code in &lt;strong&gt;ViewController.m&lt;/strong&gt; with the following:&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;ViewController.h&amp;quot;
@interface ViewController ()
{
    UIImage *img;
    UIImageView *iv;
    NSMutableArray *ivs;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    // (1) Creating a bitmap context, filling it with yellow as &amp;quot;background&amp;quot; color:
    CGSize size = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height);
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), YES, 0.0);
    [[UIColor yellowColor] setFill];
    UIRectFill(CGRectMake(0, 0, size.width, size.height));
    // (2) Create a circle via a bezier path and stroking+filling it in the bitmap context:
    UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(size.width/2, size.height/2) radius:140 startAngle:0 endAngle:2 * M_PI clockwise:YES];
    [[UIColor blackColor] setStroke];
    bezierPath.lineWidth = 5.0;
    [bezierPath stroke];
    [[UIColor redColor] setFill];
    [bezierPath fill];
    // (3) Creating an array of images:
    NSArray *rocks = @[[UIImage imageNamed:@&amp;quot;rock1&amp;quot;],
                       [UIImage imageNamed:@&amp;quot;rock2&amp;quot;],
                       [UIImage imageNamed:@&amp;quot;rock3&amp;quot;],
                       [UIImage imageNamed:@&amp;quot;rock4&amp;quot;],
                       [UIImage imageNamed:@&amp;quot;rock5&amp;quot;],
                       [UIImage imageNamed:@&amp;quot;rock6&amp;quot;],
                       [UIImage imageNamed:@&amp;quot;rock7&amp;quot;],
                       [UIImage imageNamed:@&amp;quot;rock8&amp;quot;],
                       [UIImage imageNamed:@&amp;quot;rock9&amp;quot;]];
    // (4) Drawing rocks in a loop, each chosen randomly from the image set and drawn at a random position in a circular pattern:
    for ( int i = 0; i &amp;lt; 100; i++)
    {
        int idx = arc4random() % rocks.count;
        NSLog(@&amp;quot;idx = %d&amp;quot;, idx);
        int radius = 100;
        int revolution = 360;
        float r = (float)(arc4random() % radius);
        float angle = (float)(arc4random() % revolution);
        float x = size.width/2 + r * cosf(angle * M_PI/180.0);
        float y = size.height/2 + r * sinf(angle * M_PI/180.0);
        CGSize rockSize = ((UIImage *)rocks[idx]).size;
        [rocks[idx] drawAtPoint:CGPointMake(x-rockSize.width/2, y-rockSize.height/2)];
    }
    // (5) Deriving a new UIImage instance from the bitmap context:
    UIImage *fImg = UIGraphicsGetImageFromCurrentImageContext();
    // (6) Closing the context:
    UIGraphicsEndImageContext();
    // (7) Setting the image view's image property to the created image, and displaying
    iv = [[UIImageView alloc] initWithImage:fImg];
    [self.view addSubview:iv];
}
@end
 &lt;/pre&gt;&lt;p&gt;Configure the App Delegate to use an instance of &lt;code&gt;ViewController&lt;/code&gt; as the root view controller by replacing the code in &lt;strong&gt;AppDelegate.m&lt;/strong&gt; with the following:&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;AppDelegate.h&amp;quot;
#import &amp;quot;ViewController.h&amp;quot;
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = [[ViewController alloc] init];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}
@end
&lt;/pre&gt;&lt;p&gt;Let&amp;#8217;s examine the code for &lt;code&gt;viewDidLoad:&lt;/code&gt; where all the action happens. Referring to the numbers in the code comments:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;We want to start by drawing an image, which means we need a &amp;#8220;canvas&amp;#8221;. In proper terminology, this is called an &lt;em&gt;image context&lt;/em&gt; (or bitmap context).  We create one by calling the &lt;code&gt;UIGraphicsBeginImageContextWithOptions()&lt;/code&gt; function. This function takes as arguments a &lt;code&gt;CGSize&lt;/code&gt; (which we&amp;#8217;ve set to the size of our view controller&amp;#8217;s view, meaning the entire screen), a &lt;code&gt;BOOL&lt;/code&gt; saying whether the context is opaque or not. (An opaque context is more efficient, but you can&amp;#8217;t &amp;#8220;see through&amp;#8221; it. Since there&amp;#8217;s nothing of interest underneath our context, we set it to &lt;code&gt;YES&lt;/code&gt;), A scale factor, which is a &lt;code&gt;float&lt;/code&gt; that we set to 0.0 (a value that ensures device-specific scale). Depending on whether or not the device has a Retina display, the scale factor will be set to 2.0 or 1.0 respectively. I&amp;#8217;ll talk a bit more about the scale factor shortly, but for a comprehensive discussion, I&amp;#8217;ll refer you to the official documentation (specifically, the &amp;#8220;Points vs. Pixels&amp;#8221; section in the &lt;em&gt;&amp;#8220;Drawing and Printing Guide for iOS&amp;#8221;&lt;/em&gt;).&lt;p&gt;Once we create an image context this way, it becomes the &lt;em&gt;current context&lt;/em&gt;. This is important because to draw with &lt;em&gt;UIKit&lt;/em&gt;, we must have a current drawing context where all the (implicit) drawing happens. We now set a fill color (for the current context) and fill in a rectangle (the size of the entire context).&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;We now create a &lt;code&gt;UIBezierPath&lt;/code&gt; instance in the shape of a circle, which we stroke with a thick outline and fill with a different color. This concludes the drawing portion of our image creation.&lt;/li&gt;&lt;li&gt; We create an array of images, with each image instantiated via the &lt;code&gt;imageNamed:&lt;/code&gt; initializer of &lt;code&gt;UIImage&lt;/code&gt;. It&amp;#8217;s important to observe here that we have &lt;em&gt;two&lt;/em&gt; sets of rock images: &lt;strong&gt;rock1.png, rock2.png,&amp;#8230;&lt;/strong&gt; and &lt;strong&gt;rock1@2x.png, rock2@2x.png&lt;/strong&gt;, the latter being twice the resolution of the former. One of the great features of &lt;code&gt;UIImage&lt;/code&gt; is that at runtime the &lt;code&gt;imageNamed:&lt;/code&gt; method automatically looks for an image with suffix @2x (presumed to be of double resolution) on a Retina device. If one is available, it is used! If the suffixed image is absent or if the device is non-Retina, than the standard image is used. Note that we don&amp;#8217;t specify the suffix of the image in the initializer. The use of single- and double-resolution images in conjunction with the device-dependent scale (as a result of setting &lt;code&gt;scale&lt;/code&gt; to &lt;code&gt;0.0&lt;/code&gt;) ensures the actual size of the objects on screen will be the same. Naturally, the Retina images will be more crisp because of the higher pixel density.&lt;/li&gt; If you view the rock images, you&amp;#8217;ll notice that the double-resolution images are flipped with respect to the single-resolution ones. I did that on purpose so we could confirm that at runtime the correct resolution images were being used &amp;#8211; that&amp;#8217;s all. &lt;strong&gt;Normally the two sets of images would be the same (apart from the resolution).&lt;/strong&gt;&lt;li&gt;We compose our image in a loop by placing a randomly chosen rock from our picture set at a random point (constrained to lie in a circle) in each iteration.  The &lt;code&gt;UIImage&lt;/code&gt; method &lt;code&gt;drawAtPoint:&lt;/code&gt; draws the chosen rock image at the specified point into the current image context.&lt;/li&gt;&lt;li&gt;We now extract a new &lt;code&gt;UIImage&lt;/code&gt; object from the contents of the current image context, by calling &lt;code&gt;UIGraphicsGetImageFromCurrentImageContext()&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The call to &lt;code&gt;UIGraphicsEndImageContext()&lt;/code&gt; ends the current image context and cleans up memory.&lt;/li&gt;&lt;li&gt;Finally, we set the image we created as the &lt;code&gt;image&lt;/code&gt; property of our &lt;code&gt;UIImageView&lt;/code&gt; and display it on screen.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Build and run. The output should look like the following, only randomized differently:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_5.png" alt="UIImage created by drawing and composition" /&gt;&lt;/p&gt; &lt;figcaption&gt;UIImage created by drawing and composition&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;By testing on both Retina and non-Retina devices or by changing the device type in the Simulator under the &lt;emHardware&lt;/em&gt; menu, you can ensure that the rocks are flipped with one in respect to the other. &lt;strong&gt;I reiterate that I only did this so we could easily confirm that the right set of images was being picked at runtime &amp;#8211; normally, there&amp;#8217;s no reason for you to do this!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;To recap &amp;#8211; at the risk of belaboring the point &amp;#8211; we created a new image (a &lt;code&gt;UIImage&lt;/code&gt; object) by compositing together images we already have on top of a drawing we drew.&lt;/p&gt;&lt;p&gt;On to the next part of the implementation!&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Resizable Images&lt;/h2&gt;&lt;p&gt;Consider the figure below.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_6.png" alt="A callout (left), deconstructed to show how the image might be resized sensibly (right)" /&gt;&lt;/p&gt; &lt;figcaption&gt;A callout (left), deconstructed to show how the image might be resized sensibly (right)&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;The left image shows a callout (&amp;#8220;speech bubble&amp;#8221;) similar to the one seen in many messaging apps. Obviously, we would like the callout to expand or shrink according to the amount of text in it. Also, we&amp;#8217;d like to use a single image from which we can generate callouts of any size. If we magnify the entire callout equally in all directions, the entire image gets pixellated or blurred (depending on the resizing algorithm being used). However, notice that the way the callout image has been designed, it can be expanded in certain directions without loss of quality, by simply replicating (&lt;em&gt;tiling&lt;/em&gt;) pixels as we go along. The corner shapes can&amp;#8217;t be resized without changing image quality, but on the other hand, the middle is just a block of pixels of uniform colour that can be made any size we like. The top and bottom sides can be stretched horizontally without losing quality, and the left and right sides vertically. All this is shown in the image on the right hand side.&lt;/p&gt;&lt;p&gt;Luckily for us, &lt;code&gt;UIImage&lt;/code&gt; has a couple of methods for creating resizable images of this sort. The one we&amp;#8217;re going to use is &lt;code&gt;resizableImageWithCapInsets:&lt;/code&gt;. Here the &amp;#8220;cap insets&amp;#8221; represent the dimensions of the non-stretchable corners of the image (starting from the top margin and moving counterclockwise) and are encapsulated in a &lt;code&gt;struct&lt;/code&gt; of type &lt;code&gt;UIEdgeInsets&lt;/code&gt; composed of four &lt;code&gt;float&lt;/code&gt;s:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
typedef struct {
 float top, left, bottom, right;
 } UIEdgeInsets;
&lt;/pre&gt;&lt;p&gt;The figure below should clarify what these numbers represent:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_7.png" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;Let&amp;#8217;s exploit resizable &lt;code&gt;UIImage&lt;/code&gt;s to create a simple class that lets us enclose any amount of text in a resizable image!&lt;/p&gt;&lt;p&gt;Create a &lt;code&gt;NSObject&lt;/code&gt; subclass called &lt;code&gt;Note&lt;/code&gt; and enter the following code into &lt;strong&gt;Note.h&lt;/strong&gt; and &lt;strong&gt;Note.m&lt;/strong&gt; respectively:&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
 #import &amp;lt;Foundation/Foundation.h&amp;gt;
@interface Note : NSObject
@property (nonatomic, readonly) NSString *text;
@property (nonatomic, readonly) UIImageView *noteView;
- (id)initWithText:(NSString *)text fontSize:(float)fontSize noteChrome:(UIImage *)img edgeInsets:(UIEdgeInsets)insets maximumWidth:(CGFloat)width topLeftCorner:(CGPoint)corner;
@end
&lt;/pre&gt;&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;Note.h&amp;quot;
@implementation Note
- (id)initWithText:(NSString *)text fontSize:(float)fontSize noteChrome:(UIImage *)img edgeInsets:(UIEdgeInsets)insets  maximumWidth:(CGFloat)width topLeftCorner:(CGPoint)corner
{
    if (self = [super init])
    {
#define LARGE_NUMBER 10000 // just a large (but arbitrary) number because we don't want to impose any vertical constraint on our note size
        _text = [NSString stringWithString:text];
        CGSize computedSize = [text sizeWithFont:[UIFont systemFontOfSize:fontSize] constrainedToSize:CGSizeMake(width, LARGE_NUMBER) lineBreakMode:NSLineBreakByWordWrapping];
        UILabel *textLabel = [[UILabel alloc] init];
        textLabel.font = [UIFont systemFontOfSize:fontSize];
        textLabel.text = self.text;
        textLabel.numberOfLines = 0; // unlimited number of lines
        textLabel.lineBreakMode = NSLineBreakByWordWrapping;
        textLabel.frame = CGRectMake(insets.left, insets.top, computedSize.width , computedSize.height);
        _noteView = [[UIImageView alloc] initWithFrame:CGRectMake(corner.x, corner.y, textLabel.bounds.size.width+insets.left+insets.right, textLabel.bounds.size.height+insets.top+insets.bottom)];
        _noteView.image = [img resizableImageWithCapInsets:insets];
        [_noteView addSubview:textLabel];
    }
    return self;
}
@end
&lt;/pre&gt;&lt;p&gt;The initializer method for &lt;code&gt;Note&lt;/code&gt;, &lt;code&gt;-initWithText:fontSize: noteChrome:edgeInsets:maximumWidth:topLeftCorner:&lt;/code&gt; takes several parameters: the text string to be displayed, the font size, the note &amp;#8220;chrome&amp;#8221; (which is the resizable &lt;code&gt;UIImage&lt;/code&gt; that will surround the text),  its cap insets, the maximum width the note&amp;#8217;s image view may have, and the top-left corner of the note&amp;#8217;s frame.&lt;/p&gt;&lt;p&gt;Once initialised, the &lt;code&gt;Note&lt;/code&gt; class&amp;#8217; &lt;code&gt;noteView&lt;/code&gt; property (of type &lt;code&gt;UIImageView&lt;/code&gt;) is the user interface element that we&amp;#8217;ll display on the screen.&lt;/p&gt;&lt;p&gt;The implementation is quite simple: we exploit a very useful method from the &lt;code&gt;NSString&lt;/code&gt;&amp;#8216;s category on &lt;em&gt;UIKit&lt;/em&gt;, &lt;code&gt;sizeWithFont:constrainedToSize:lineBreakMode:&lt;/code&gt;, that computes the size that a block of text will occupy on the screen, given certain parameters. Once we&amp;#8217;ve done that, we construct a text label (&lt;code&gt;UILabel&lt;/code&gt;) and populate it with the provided text. By taking into account the inset sizes and the calculated text size, we assign the label an appropriate frame, as well as make our &lt;code&gt;noteView&lt;/code&gt;&amp;#8216;s &lt;code&gt;image&lt;/code&gt; large enough (using the &lt;code&gt;resizableImageWithCapInsets&lt;/code&gt; method) so that the label fits comfortably on top of the interior (resizable) area of the the image.&lt;/p&gt;&lt;p&gt;In the figure below, the image on the left represents what a typical note containing a few lines worth of text in it would look like.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_8.png" alt="Using the smallest possible image for constructing a resizable image" /&gt;&lt;/p&gt; &lt;figcaption&gt;Using the smallest possible image for constructing a resizable image&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;Note that the interior has nothing of interest. We can actually &amp;#8220;pare&amp;#8221; the image to its bare minimum (as shown on the right) by getting rid of all the pixels in the interior with image editing software. In fact, in the documentation Apple recommends that for best performance, the interior area should be tiled 1 x 1 pixels. That&amp;#8217;s what the funny little image on the right represents, and that&amp;#8217;s the one we&amp;#8217;re going to be passing to our &lt;code&gt;Note&lt;/code&gt; initializer. Make sure that it got added to your project as &lt;strong&gt;squeezednote.png&lt;/strong&gt; when you dragged the &lt;em&gt;Images&lt;/em&gt; folder to your project.&lt;/p&gt;&lt;p&gt;In &lt;code&gt;ViewController.m&lt;/code&gt;, enter the &lt;code&gt;#import "Note.h"&lt;/code&gt; statement at the top. Comment out the previous &lt;code&gt;viewDidLoad:&lt;/code&gt; form and enter the following:&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)viewDidLoad
{
    [super viewDidLoad];
    NSString *text1 = @&amp;quot;Hi!&amp;quot;;
    NSString *text2 = @&amp;quot;I size myself according to my content!&amp;quot;;
    NSString *text3 = @&amp;quot;Standard boring random text: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.&amp;quot;;
    UIImage *noteChrome = [UIImage imageNamed:@&amp;quot;squeezednote&amp;quot;];
    UIEdgeInsets edgeInsets = UIEdgeInsetsMake(37, 12, 12, 12);
    Note *note1 = [[Note alloc] initWithText:text1 fontSize:25.0 noteChrome:noteChrome edgeInsets:edgeInsets maximumWidth:300 topLeftCorner:CGPointMake(10, 10)];
    Note *note2 = [[Note alloc] initWithText:text2 fontSize:30.0 noteChrome:noteChrome edgeInsets:edgeInsets maximumWidth:300 topLeftCorner:CGPointMake(200, 10)];
    Note *note3 = [[Note alloc] initWithText:text3 fontSize:16.0 noteChrome:noteChrome edgeInsets:edgeInsets maximumWidth:300 topLeftCorner:CGPointMake(10, 200)];
    [self.view addSubview:note1.noteView];
    [self.view addSubview:note2.noteView];
    [self.view addSubview:note3.noteView];
}
&lt;/pre&gt;&lt;p&gt;We&amp;#8217;re simply creating &lt;code&gt;Note&lt;/code&gt; objects with a different amount of text. Build, run, and observe how nicely the &amp;#8220;chrome&amp;#8221; around the note resizes to accommodate the text inside its boundaries.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_9.png" alt="Nicely resizing note" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;figcaption&gt;Nicely resizing note&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;For the sake of comparison, here&amp;#8217;s what the output would look like if &amp;#8220;squeezednote.png&amp;#8221; were configured as a &amp;#8220;normal&amp;#8221; &lt;code&gt;UIImage&lt;/code&gt; (i.e., instantiated with &lt;code&gt;imageNamed:&lt;/code&gt;, and that resized equally in all directions).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_10.png" /&gt;&lt;/p&gt; &lt;figcaption&gt;Badly resizing note&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;Admittedly, we wouldn&amp;#8217;t actually use a &amp;#8220;minimal&amp;#8221; image like &amp;#8220;squeezednote&amp;#8221; unless we were using resizable images in the first place, so the effect shown in the previous screenshot is greatly exaggerated. However, the blurring problem would definitely be there.&lt;/p&gt;&lt;/p&gt;&lt;p&gt;On to the final part of the tutorial!&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Animated Images&lt;/h2&gt;&lt;p&gt;By an &amp;#8220;animated image&amp;#8221;, I actually mean a sequence of individual 2D images that are displayed in succession. This is basically just the sprite animation that is used in most 2D games. &lt;code&gt;UIImage&lt;/code&gt; has an initializer method &lt;code&gt;animatedImageNamed:duration:&lt;/code&gt; to which you pass a string that represents the prefix of the sequence of images to be animated, so if your images are named &lt;em&gt;&amp;#8220;robot1.png&amp;#8221;, &amp;#8220;robot2.png&amp;#8221;, &amp;#8230;, &amp;#8220;robot60.png&amp;#8221;&lt;/em&gt;, you&amp;#8217;d simply pass in the string &amp;#8220;robot&amp;#8221; to this method. The duration of the animation is also passed in. That&amp;#8217;s pretty much it! When the image is added to a &lt;code&gt;UIImageView&lt;/code&gt;, it continuously animates on screen. Let&amp;#8217;s implement an example.&lt;/p&gt;&lt;p&gt;Comment out the previous version of &lt;code&gt;viewDidLoad:&lt;/code&gt; and enter the following version:&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
 - (void)viewDidLoad
{
    [super viewDidLoad];
    ivs = [NSMutableArray array];
    img = [UIImage animatedImageNamed:@&amp;quot;explosion&amp;quot; duration:2.0];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(explosion:)];
    [self.view addGestureRecognizer:tap];
}
- (void)explosion:(UITapGestureRecognizer *)t
{
    CGPoint loc = [t locationInView:self.view];
    for (UIImageView *v in ivs)
    {
        if ([v pointInside:[v convertPoint:loc fromView:self.view] withEvent:nil])
        {
            [ivs removeObject:v];
            [v removeFromSuperview];
            return;
        }
    }
    UIImageView *v = [[UIImageView alloc] initWithImage:img];
    v.center = loc;
    [ivs addObject:v];
    [self.view addSubview:v];
}
&lt;/pre&gt;&lt;p&gt;We added a set of PNG images to our project, &lt;strong&gt;explosion1.png&lt;/strong&gt; through &lt;strong&gt;explosion81.png&lt;/strong&gt; which represent an animated sequence of a fiery explosion. Our code is quite simple: we detect a tap on the screen and either place a new explosion animation at the tap point, or if there was already an explosion going on at that point, we remove it. Note that the essential code consists of just creating an animated image via &lt;code&gt;animatedImageNamed:&lt;/code&gt; to which we pass the string &lt;code&gt;@"explosion"&lt;/code&gt; and a float value for the duration.&lt;/p&gt;&lt;p&gt;You&amp;#8217;ll have to run the app on the simulator or a device yourself in order to enjoy the fireworks display, but here&amp;#8217;s an image that captures a single frame of the action, with several explosions going on at the same time:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Advanced-Features-of-the-UIImage-Class_11.png" alt="Animated explosions" /&gt;&lt;/p&gt; &lt;figcaption&gt;Animated explosions&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;Admittedly, if you were developing a high-paced action game such as a shoot &amp;#8216;em up or a side scrolling platformer, then &lt;code&gt;UIImage&lt;/code&gt;&amp;#8216;s support for animated images would seem quite primitive and wouldn&amp;#8217;t be your go-to approach for implementing animation. Really, that&amp;#8217;s not what the &lt;code&gt;UIImage&lt;/code&gt; has been built for, but in other (less demanding) scenarios, it might be just the ticket! Since the animation runs continuously until you remove the animated image or the image view from the interface, you could make the animations stop after a prescribed time interval by sending a delayed message with &lt;code&gt;– performSelector:withObject:afterDelay:&lt;/code&gt; or use an &lt;code&gt;NSTimer&lt;/code&gt;.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;In this tutorial, we looked at some useful but less commonly-known features of the &lt;code&gt;UIImage&lt;/code&gt; class that can occasionally come in handy. I suggest you take a look at the &lt;strong&gt;&lt;code&gt;UIImage&lt;/code&gt; Class Reference&lt;/strong&gt; because there are more options to some of the features we discussed in this tutorial. For example, images can be composited using one of several &lt;em&gt;blending options&lt;/em&gt;. Resizable images can be configured in one of two &lt;em&gt;resizing modes&lt;/em&gt;, tiling (which is the one we used implicitly) or stretching. Even animated images can have insets. We didn&amp;#8217;t talk about the underlying &lt;code&gt;CGImage&lt;/code&gt; opaque type that &lt;code&gt;UIImage&lt;/code&gt; wraps around. You need to deal with &lt;code&gt;CGImage&lt;/code&gt;s if you program at the &lt;em&gt;Core Graphics&lt;/em&gt; level, which is the C-based API that sits one level below &lt;em&gt;UIKit&lt;/em&gt; in the iOS framework. &lt;em&gt;Core Graphics&lt;/em&gt; is more powerful than &lt;em&gt;UIKit&lt;/em&gt; to program with &amp;#8211; but, on the flip side, not quite as easy. We also didn&amp;#8217;t talk about images created with data from a &lt;em&gt;Core Image&lt;/em&gt; object, as that would make more sense in a &lt;em&gt;Core Image&lt;/em&gt; tutorial.&lt;/p&gt;&lt;p&gt;Hope you found this tutorial useful. Keep coding!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/wPO8XSmQptY" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-advanced-uiimage-techniques/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-advanced-uiimage-techniques/</feedburner:origLink></item> <item><title>Android SDK: Create a Barcode Reader</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/bzQQMhhUhW0/</link> <comments>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-a-barcode-reader/#comments</comments> <pubDate>Tue, 21 May 2013 11:30:28 +0000</pubDate> <dc:creator>Sue Smith</dc:creator> <category><![CDATA[Android SDK]]></category> <category><![CDATA[android]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17162</guid> <description>&lt;p&gt;In this tutorial, we&amp;#8217;ll use the ZXing (Zebra Crossing) library to carry out barcode scanning within an Android app. We&amp;#8217;ll call on the resources in this open source library within our app, retrieving and processing the returned results.&lt;br
/&gt;&lt;/p&gt;&lt;p&gt;Since we&amp;#8217;re using the &lt;a
href="http://code.google.com/p/zxing/"&gt;ZXing&lt;/a&gt; library, we don&amp;#8217;t need to worry about users without the barcode scanner installed, because the integration classes provided will take care of this for us. By importing the ZXing integration classes into our app, we can make user scans easier and focus our development efforts on handling the scan results. In a follow-up series coming soon, we&amp;#8217;ll develop a book scanning app where we&amp;#8217;ll build on the app we created in this tutorial. We&amp;#8217;ll also add support for Google Books API so that we can display information about scanned books.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Create a New Android Project&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; In Eclipse, create a new Android project. Enter your chosen application, project, and package names. Let Eclipse create a blank &lt;strong&gt;activity&lt;/strong&gt; for you, with the name of your choice for both the &lt;strong&gt;activity&lt;/strong&gt; and its layout.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Using-Barcode-Scanning-In-Android-Apps_1.png" alt="New Project" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; Open your main layout file. With the default settings, Eclipse starts your layout with a &lt;strong&gt;Relative Layout&lt;/strong&gt; object, which you can leave as is. Inside of it, replace the existing content (typically a &lt;strong&gt;Text View&lt;/strong&gt;) with a button.&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;RelativeLayout xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;
	xmlns:tools=&amp;quot;http://schemas.android.com/tools&amp;quot;
	android:layout_width=&amp;quot;match_parent&amp;quot;
	android:layout_height=&amp;quot;match_parent&amp;quot; &amp;gt;
	&amp;lt;Button android:id=&amp;quot;@+id/scan_button&amp;quot;
		android:layout_width=&amp;quot;wrap_content&amp;quot;
		android:layout_height=&amp;quot;wrap_content&amp;quot;
		android:layout_centerHorizontal=&amp;quot;true&amp;quot;
		android:text=&amp;quot;@string/scan&amp;quot; /&amp;gt;
&amp;lt;/RelativeLayout&amp;gt;
&lt;/pre&gt;&lt;p&gt; After the button, add two &lt;strong&gt;Text Views&lt;/strong&gt; in which we will output scanning information.&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;TextView
	android:id=&amp;quot;@+id/scan_format&amp;quot;
	android:layout_width=&amp;quot;wrap_content&amp;quot;
	android:layout_height=&amp;quot;wrap_content&amp;quot;
	android:textIsSelectable=&amp;quot;true&amp;quot;
	android:layout_centerHorizontal=&amp;quot;true&amp;quot;
	android:layout_below=&amp;quot;@id/scan_button&amp;quot; /&amp;gt;
&amp;lt;TextView
	android:id=&amp;quot;@+id/scan_content&amp;quot;
	android:layout_width=&amp;quot;wrap_content&amp;quot;
	android:layout_height=&amp;quot;wrap_content&amp;quot;
	android:textIsSelectable=&amp;quot;true&amp;quot;
	android:layout_centerHorizontal=&amp;quot;true&amp;quot;
	android:layout_below=&amp;quot;@id/scan_format&amp;quot; /&amp;gt;
&lt;/pre&gt;&lt;p&gt; Add the button text string to your &amp;#8220;&lt;strong&gt;res/values/strings&lt;/strong&gt;&amp;#8221; XML file.&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;string name=&amp;quot;scan&amp;quot;&amp;gt;Scan&amp;lt;/string&amp;gt;
&lt;/pre&gt;&lt;p&gt; The user will press the button to scan. When the app receives a result from the barcode scanning operation, it will display the scan content data and format name in the two &lt;strong&gt;Text Views&lt;/strong&gt;.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Add ZXing to Your Project&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; ZXing is an open source library that provides access to tested and functional barcode scanning on Android. Many users will already have the app installed on their devices, so you can simply launch the scanning &lt;strong&gt;Intents&lt;/strong&gt; and retrieve the results. In this tutorial we are going to use the &lt;a
href="http://code.google.com/p/zxing/wiki/ScanningViaIntent"&gt;Scanning via Intent&lt;/a&gt; method to make scanning easier. This method involves importing a couple of classes into your app and lets ZXing take care of instances where the user does not have the scanner installed. If the user doesn&amp;#8217;t have the barcode scanner installed, they&amp;#8217;ll be prompted to download it.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Since ZXing is open source, you can import the source code into your projects in its entirety. However, this is really only advisable if you need to make changes to its functionality. You can also compile the project and include its JAR file in your own apps if you prefer. For most purposes, using &lt;strong&gt;Scanning via Intent&lt;/strong&gt; is a reliable and easy to implement options, plus your users will have access to the most recent version of the ZXing app.&lt;/p&gt;&lt;p&gt; In Eclipse, add a new package to your project by right-clicking the &amp;#8220;&lt;strong&gt;src&lt;/strong&gt;&amp;#8221; folder and choosing &amp;#8220;&lt;strong&gt;New&lt;/strong&gt;&amp;#8220;, then &amp;#8220;&lt;strong&gt;Package&lt;/strong&gt;&amp;#8220;, and entering &amp;#8220;&lt;strong&gt;com.google.zxing.integration.android&lt;/strong&gt;&amp;#8221; as the package name.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Using-Barcode-Scanning-in-Android-Apps_2.png" alt="New Package" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; Eclipse offers several ways to import existing code into your projects. For the purposes of this tutorial, you&amp;#8217;ll probably find it easiest to simply create the two required classes and copy the code from ZXing. Right-click your new package, choose &amp;#8220;&lt;strong&gt;New&lt;/strong&gt;&amp;#8221; then &amp;#8220;&lt;strong&gt;Class&lt;/strong&gt;&amp;#8221; and enter &amp;#8220;&lt;strong&gt;IntentIntegrator&lt;/strong&gt;&amp;#8221; as the class name. You can leave the other default settings the way they are. Once you&amp;#8217;ve created this class, do the same for the other class we&amp;#8217;ll be importing, giving it &amp;#8220;&lt;strong&gt;IntentResult&lt;/strong&gt;&amp;#8221; as its class name.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Using-Barcode-Scanning-in-Android-Apps_3.png" alt="New Class" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt; Copy the code from both classes in the ZXing library and paste it into the class files you created. These are &lt;a
href="http://code.google.com/p/zxing/source/browse/trunk/android-integration/src/com/google/zxing/integration/android/IntentIntegrator.java"&gt;IntentIntegrator&lt;/a&gt; and &lt;a
href="http://code.google.com/p/zxing/source/browse/trunk/android-integration/src/com/google/zxing/integration/android/IntentResult.java"&gt;IntentResult&lt;/a&gt;. Refer to the source code download if you&amp;#8217;re in any doubt about where the various files and folders should be or what should be in them.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Using-Barcode-Scanning-in-Android-Apps_4.png" alt="Project Package" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt; You can now import the ZXing classes into your main &lt;strong&gt;Activity&lt;/strong&gt; class.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
&lt;/pre&gt;&lt;p&gt; Go ahead and add the other import statements we&amp;#8217;ll use for this tutorial. Bear in mind that Eclipse may have already added some for you.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
&lt;/pre&gt;&lt;p&gt; Feel free to have a look at the content of the two ZXing classes. It&amp;#8217;s fairly straightforward, but the details of the barcode scanning processing are carried out elsewhere in the library. These two classes really act as an interface to the scanning functionality.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Do Some Scanning&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; Let&amp;#8217;s implement scanning when the user clicks the button we added. In your app&amp;#8217;s main &lt;strong&gt;activity&lt;/strong&gt; class, the default &lt;strong&gt;onCreate&lt;/strong&gt; method entered by Eclipse should look something like this.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
}
&lt;/pre&gt;&lt;p&gt; Above this method, add the following instance variables to represent the button and two &lt;strong&gt;Text Views&lt;/strong&gt; we created in the layout file.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
private Button scanBtn;
private TextView formatTxt, contentTxt;
&lt;/pre&gt;&lt;p&gt; In &lt;strong&gt;onCreate&lt;/strong&gt;, after the existing code, instantiate these variables using the ID values we specified in the XML.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
scanBtn = (Button)findViewById(R.id.scan_button);
formatTxt = (TextView)findViewById(R.id.scan_format);
contentTxt = (TextView)findViewById(R.id.scan_content);
&lt;/pre&gt;&lt;p&gt; Next, add a listener to the button so that we can handle presses.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
scanBtn.setOnClickListener(this);
&lt;/pre&gt;&lt;p&gt; Extend the opening line of the class declaration to implement the &lt;strong&gt;OnClickListener&lt;/strong&gt; interface.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
public class MainActivity extends Activity implements OnClickListener
&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; Now we can respond to button clicks by starting the scanning process. Add an &lt;strong&gt;onClick&lt;/strong&gt; method to your &lt;strong&gt;activity&lt;/strong&gt; class.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
public void onClick(View v){
//respond to clicks
}
&lt;/pre&gt;&lt;p&gt; Check whether the scanning button has been pressed inside this method.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
if(v.getId()==R.id.scan_button){
//scan
}
&lt;/pre&gt;&lt;p&gt; Inside this conditional block, create an instance of the &lt;Strong&gt;Intent Integrator&lt;/strong&gt; class we imported.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
IntentIntegrator scanIntegrator = new IntentIntegrator(this);
&lt;/pre&gt;&lt;p&gt; Now we can call on the &lt;strong&gt;Intent Integrator&lt;/strong&gt; method to start scanning.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
scanIntegrator.initiateScan();
&lt;/pre&gt;&lt;p&gt; At this point, the scanner will start if it&amp;#8217;s installed on the user&amp;#8217;s device. If not, they&amp;#8217;ll be prompted to download it. The results of the scan will be returned to the main &lt;strong&gt;activity&lt;/strong&gt; where scanning was initiated, so we&amp;#8217;ll be able to retrieve it in the &lt;em&gt;onActivityResult&lt;/em&gt; method.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; When you call the &lt;strong&gt;initiateScan&lt;/strong&gt; method, you can choose to pass a collection of the barcode types you want to scan. By default, the method will scan for all supported types. These include UPC-A, UPC-E, EAN-8, EAN-13, QR Code, RSS-14, RSS Expanded, Data Matrix, Aztec, PDF 417, Codabar, ITF, Codes 39, 93, and 128. The ZXing library also includes barcode scanning options that we&amp;#8217;re not going to cover in this tutorial. You can check the project out at &lt;a
href="http://code.google.com/p/zxing/"&gt;Google Code&lt;/a&gt; for more info.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Retrieve Scanning Results&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; When the user clicks the scan button, the barcode scanner will launch. When they scan a barcode, it will return the scanned data to the &lt;strong&gt;onActivityResult&lt;/strong&gt; method of the calling &lt;strong&gt;activity&lt;/strong&gt;. Add the method to your main &lt;strong&gt;activity&lt;/strong&gt; class.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
//retrieve scan result
}
&lt;/pre&gt;&lt;p&gt; Inside the method, try to parse the result into an instance of the ZXing Intent Result class we imported.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; As with any data being retrieved from another app, it&amp;#8217;s vital to check for null values. Only proceed if we have a valid result.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
if (scanningResult != null) {
//we have a result
}
&lt;/pre&gt;&lt;p&gt; If scan data is not received (for example, if the user cancels the scan by pressing the back button), we can simply output a message.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
else{
	Toast toast = Toast.makeText(getApplicationContext(),
		&amp;quot;No scan data received!&amp;quot;, Toast.LENGTH_SHORT);
	toast.show();
}
&lt;/pre&gt;&lt;p&gt; Back in the &lt;strong&gt;if&lt;/strong&gt; block, let&amp;#8217;s find out what data the scan returned. The &lt;strong&gt;Intent Result&lt;/strong&gt; object provides methods to retrieve the content of the scan and the format of the data returned from it. Retrieve the content as a string value.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
String scanContent = scanningResult.getContents();
&lt;/pre&gt;&lt;p&gt; Retrieve the format name, also as a string.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
String scanFormat = scanningResult.getFormatName();
&lt;/pre&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt; Now your program has the format and content of the scanned data, so you can do whatever you want with it. For the purpose of this tutorial, we&amp;#8217;ll just write the values to the &lt;strong&gt;Text Views&lt;/strong&gt; in our layout.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
formatTxt.setText(&amp;quot;FORMAT: &amp;quot; + scanFormat);
contentTxt.setText(&amp;quot;CONTENT: &amp;quot; + scanContent);
&lt;/pre&gt;&lt;p&gt; Run your app on a device instead of an emulator so that you can see the scan functioning. Try scanning a book or any other barcode you might have.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Using-Barcode-Scanning-in-Android-Apps_5.png" alt="App During Scanning" /&gt;&lt;/p&gt; &lt;figcaption&gt;When the scan is initiated, the user is taken to the ZXing app to scan a barcode.&lt;/figcaption&gt; &lt;/figure&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Using-Barcode-Scanning-in-Android-Apps_6.png" alt="Scan Result" /&gt;&lt;/p&gt; &lt;figcaption&gt;The scan results are returned to the app.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt; In this tutorial, we&amp;#8217;ve run through the process of facilitating barcode scanning within Android apps using the ZXing library. In your own apps, you might want to carry out further processing on the retrieved scan results, such as loading URLs or looking the data up in a third party data source. In the follow-up to this tutorial, we&amp;#8217;ll use the barcode scanning functionality to create a book scanning app that will allow us to retrieve data about scanned books from the Google Books API.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/bzQQMhhUhW0" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-a-barcode-reader/feed/</wfw:commentRss> <slash:comments>2</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-a-barcode-reader/</feedburner:origLink></item> <item><title>Create a Weather App with Forecast – API Integration</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/TjrrRLNQudk/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-api-integration/#comments</comments> <pubDate>Mon, 20 May 2013 19:42:53 +0000</pubDate> <dc:creator>Bart Jacobs</dc:creator> <category><![CDATA[iOS SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17440</guid> <description>&lt;p&gt;In the &lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-project-setup/"&gt;first article of this series&lt;/a&gt;, we laid the foundation of the project by setting up the project and creating the application&amp;#8217;s structure. In this article, we leverage the AFNetworking library to interact with the Forecast API.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Introduction&lt;/h2&gt;&lt;p&gt;In the &lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-project-setup/"&gt;first installment&lt;/a&gt; of this series, we laid the foundation of our weather application. Users can add their current location and switch between locations. In this tutorial, we will use the AFNetworking library to ask the Forecast API for the weather data of the currently selected location.&lt;/p&gt;&lt;p&gt;If you want to follow along, you will need a Forecast API key. You can obtain an API key by registering as a developer at &lt;a
href="https://developer.forecast.io/log_in"&gt;Forecast&lt;/a&gt;. Registration is free, so I encourage you to try out the Forecast weather service. You can find your API key at the bottom of your dashboard (figure 1).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130518-1.png" alt="Create a Weather App with Forecast – Forecast Integration - Obtaining Your API Key " /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 1: Obtaining Your API Key&lt;/figcaption&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Subclassing &lt;code&gt;AFHTTPClient&lt;/code&gt;&lt;/h2&gt;&lt;p&gt;As I wrote earlier in this article, we will be using the &lt;strong&gt;AFNetworking&lt;/strong&gt; library for communicating with the Forecast API. There are several options when working with AFNetworking, but to make our application future proof, we will opt for the &lt;code&gt;AFHTTPClient&lt;/code&gt; class. This class is designed for consuming web services, such as the Forecast API. Even though we will only access one API endpoint, it is still useful to make use of the &lt;code&gt;AFHTTPClient&lt;/code&gt; as you will learn in a few moments.&lt;/p&gt;&lt;p&gt;It is recommended to create an &lt;code&gt;AFHTTPClient&lt;/code&gt; subclass for each web service. Because we already added AFNetworking to our project in the previous tutorial, we can immediately start subclassing &lt;code&gt;AFHTTPClient&lt;/code&gt;.&lt;/p&gt;&lt;h3&gt;Step 1: Create the Class&lt;/h3&gt;&lt;p&gt;Create a new Objective-C class, name it &lt;code&gt;MTForecastClient&lt;/code&gt;, and make it a subclass of &lt;code&gt;AFHTTPClient&lt;/code&gt; (figure 2).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130518-2.png" alt="Create a Weather App with Forecast – Forecast Integration - Subclassing AFHTTPClient " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 2: Subclassing AFHTTPClient&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 2: Creating a Singleton Object&lt;/h3&gt;&lt;p&gt;We will adopt the singleton pattern to make it easier to use the &lt;code&gt;MTForecastClient&lt;/code&gt; class in our project. This means that only one instance of the class is alive at any one time for the lifetime of the application. Chances are that you are already familiar with singleton pattern as it is a common pattern in many object-oriented programming languages. At first glance, the singleton pattern seems very convenient, but there are a number of caveats to watch out for. You can learn more about singletons by reading &lt;a
href="http://www.cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html"&gt;this excellent article&lt;/a&gt; by Matt Gallagher.&lt;/p&gt;&lt;p&gt;Creating a singleton object is pretty straightforward in Objective-C. Start by declaring a class method in &lt;strong&gt;MTForecastClient.h&lt;/strong&gt; to provide public access to the singleton object (see below).&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;AFHTTPClient.h&amp;quot;
@interface MTForecastClient : AFHTTPClient
#pragma mark -
#pragma mark Shared Client
+ (MTForecastClient *)sharedClient;
@end
&lt;/pre&gt;&lt;p&gt;The implementation of &lt;code&gt;sharedClient&lt;/code&gt; may look daunting at first, but it isn&amp;#8217;t that difficult once you understand what&amp;#8217;s going on. We first declare two static variables, (1) &lt;code&gt;predicate&lt;/code&gt; of type &lt;code&gt;dispatch_once_t&lt;/code&gt; and (2) &lt;code&gt;_sharedClient&lt;/code&gt; of type &lt;code&gt;MTForecastClient&lt;/code&gt;. As its name implies, &lt;code&gt;predicate&lt;/code&gt; is a predicate that we use in combination with the &lt;code&gt;dispatch_once&lt;/code&gt; function. When working with a variable of type &lt;code&gt;dispatch_once_t&lt;/code&gt;, it is important that it is declared statically. The second variable, &lt;code&gt;_sharedClient&lt;/code&gt;, will store a reference to the singleton object.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;dispatch_once&lt;/code&gt; function takes a pointer to a &lt;code&gt;dispatch_once_t&lt;/code&gt; structure, the predicate, and a block. The beauty of &lt;code&gt;dispatch_once&lt;/code&gt; is that it will execute the block once for the lifetime of the application, which is exactly what we want. The &lt;code&gt;dispatch_once&lt;/code&gt; function doesn&amp;#8217;t have many uses, but this is definitely one of them. In the block that we pass to &lt;code&gt;dispatch_once&lt;/code&gt;, we create the singleton object and store a reference in &lt;code&gt;_sharedClient&lt;/code&gt;. It is safer to invoke &lt;code&gt;alloc&lt;/code&gt; and &lt;code&gt;init&lt;/code&gt; separately to avoid a race condition that could potentially lead to a deadlock. Euh &amp;#8230; what? You can read more about the nitty gritty details on &lt;a
href="http://stackoverflow.com/questions/2199106/thread-safe-instantiation-of-a-singleton"&gt;Stack Overflow&lt;/a&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
+ (MTForecastClient *)sharedClient {
    static dispatch_once_t predicate;
    static MTForecastClient *_sharedClient = nil;
    dispatch_once(&amp;amp;predicate, ^{
        _sharedClient = [self alloc];
        _sharedClient = [_sharedClient initWithBaseURL:[self baseURL]];
    });
    return _sharedClient;
}
&lt;/pre&gt;&lt;p&gt;The important thing to understand about the implementation of the &lt;code&gt;sharedClient&lt;/code&gt; class method is that the initializer, &lt;code&gt;initWithBaseURL:&lt;/code&gt;, is invoked only once. The singleton object is stored in the &lt;code&gt;_sharedClient&lt;/code&gt; static variable, which is returned by the &lt;code&gt;sharedClient&lt;/code&gt; class method.&lt;/p&gt;&lt;h3&gt;Step 3: Configuring the Client&lt;/h3&gt;&lt;p&gt;In &lt;code&gt;sharedClient&lt;/code&gt;, we invoke &lt;code&gt;initWithBaseURL:&lt;/code&gt;, which in turn invokes &lt;code&gt;baseURL&lt;/code&gt;, another class method. In &lt;code&gt;initWithBaseURL:&lt;/code&gt;, we set a default header, which means that the client adds this header to every request that it sends. This is one of the advantages of working with the &lt;code&gt;AFHTTPClient&lt;/code&gt; class. In &lt;code&gt;initWithBaseURL:&lt;/code&gt;, we also register an HTTP operation class by invoking &lt;code&gt;registerHTTPOperationClass:&lt;/code&gt;. The AFNetworking library provides a number of specialized operations classes. One of these classes is the &lt;code&gt;AFJSONRequestOperation&lt;/code&gt; class, which makes interacting with a JSON API very easy. Because the Forecast API returns a JSON response, the &lt;code&gt;AFJSONRequestOperation&lt;/code&gt; class is a good choice. The &lt;code&gt;registerHTTPOperationClass:&lt;/code&gt; method works similar to how the &lt;code&gt;registerClass:forCellReuseIdentifier:&lt;/code&gt; of the &lt;code&gt;UITableView&lt;/code&gt; class works. By telling the client what operation class we want to use for interacting with the web service, it will instantiate instances of that class for us under the hood. Why this is useful will become clear in a few moments.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithBaseURL:(NSURL *)url {
    self = [super initWithBaseURL:url];
    if (self) {
        // Accept HTTP Header
        [self setDefaultHeader:@&amp;quot;Accept&amp;quot; value:@&amp;quot;application/json&amp;quot;];
        // Register HTTP Operation Class
        [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
    }
    return self;
}
&lt;/pre&gt;&lt;p&gt;The implementation of &lt;code&gt;baseURL&lt;/code&gt; is nothing more than a convenience method for constructing the client&amp;#8217;s base URL. The base URL is the URL that the client uses to reach the web service. It is the URL without any method names or parameters. The base URL for the Forecast API is &lt;code&gt;https://api.forecast.io/forecast/&lt;API_KEY&gt;/&lt;/code&gt;. The API key is part of the URL as you can see. This may seem insecure and it actually is. It isn&amp;#8217;t difficult for someone to grab the API key so it is advisable to work with a proxy to mask the API key. Because this approach is a bit more involved, I won&amp;#8217;t cover this aspect in this series.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
+ (NSURL *)baseURL {
    return [NSURL URLWithString:[NSString stringWithFormat:@&amp;quot;https://api.forecast.io/forecast/%@/&amp;quot;, MTForecastAPIKey]];
}
&lt;/pre&gt;&lt;p&gt;You may have noticed in the implementation of &lt;code&gt;baseURL&lt;/code&gt; that I have used another string constant for storing the API key. This might seem unnecessary since we only use the API key in one location. However, it is good practice to store application data in one location or in a property list.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#pragma mark -
#pragma mark Forecast API
extern NSString * const MTForecastAPIKey;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
#pragma mark -
#pragma mark Forecast API
NSString * const MTForecastAPIKey = @&amp;quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&amp;quot;;
&lt;/pre&gt;&lt;h3&gt;Step 4: Adding a Helper Method&lt;/h3&gt;&lt;p&gt;Before we move on, I would like to extend the &lt;code&gt;MTForecastClient&lt;/code&gt; class by adding a helper or convenience method that will make it easier to query the Forecast API. This convenience method will accept a location and a completion block. The completion block is executed when the request finishes. To make working with blocks easier, it is recommended to declare a custom block type as shown below. If you still feel uncomfortable using blocks, then I recommend reading &lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/understanding-objective-c-blocks/"&gt;this great article&lt;/a&gt; by &lt;a
href="http://mobile.tutsplus.com/author/akiel-khan/"&gt;Akiel Khan&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The block takes two arguments, (1) a boolean indicating whether the query was successful and (2) a dictionary with the response from the query. The convenience method, &lt;code&gt;requestWeatherForCoordinate:completion:&lt;/code&gt;, takes the coordinates of a location (&lt;code&gt;CLLocationCoordinate2D&lt;/code&gt;) and a completion block. By using a completion block, we can avoid creating a custom delegate protocol or fall back to using notifications. Blocks are a perfect fit for this type of scenario.&lt;/code&gt;&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;AFHTTPClient.h&amp;quot;
typedef void (^MTForecastClientCompletionBlock)(BOOL success, NSDictionary *response);
@interface MTForecastClient : AFHTTPClient
#pragma mark -
#pragma mark Shared Client
+ (MTForecastClient *)sharedClient;
#pragma mark -
#pragma mark Instance Methods
- (void)requestWeatherForCoordinate:(CLLocationCoordinate2D)coordinate completion:(MTForecastClientCompletionBlock)completion;
@end
&lt;/pre&gt;&lt;p&gt;&lt;code&gt;In &lt;code&gt;requestWeatherForCoordinate:completion:&lt;/code&gt;, we invoke &lt;code&gt;getPath:success:failure:&lt;/code&gt;, a method declared in &lt;code&gt;AFHTTPClient&lt;/code&gt;. The first argument is the path that is appended to the base URL that we created earlier. The second and third arguments are blocks that are executed when the request succeeds and fails, respectively. The success and failure blocks are pretty simple. If a completion block was passed to &lt;code&gt;requestWeatherForCoordinate:completion:&lt;/code&gt;, we execute the block and pass a boolean value and the response dictionary (or &lt;code&gt;nil&lt;/code&gt; in the failure block). In the failure block, we log the error from the failure block to the console to facilitate debugging.&lt;/code&gt;&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)requestWeatherForCoordinate:(CLLocationCoordinate2D)coordinate completion:(MTForecastClientCompletionBlock)completion {
    NSString *path = [NSString stringWithFormat:@&amp;quot;%f,%f&amp;quot;, coordinate.latitude, coordinate.longitude];
    [self getPath:path parameters:nil success:^(AFHTTPRequestOperation *operation, id response) {
        if (completion) {
            completion(YES, response);
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        if (completion) {
            completion(NO, nil);
            NSLog(@&amp;quot;Unable to fetch weather data due to error %@ with user info %@.&amp;quot;, error, error.userInfo);
        }
    }];
}
&lt;/pre&gt;&lt;p&gt;You may be wondering what the &lt;code&gt;response&lt;/code&gt; object in the success blocks is or references. Even though the Forecast API returns a JSON response, the &lt;code&gt;response&lt;/code&gt; object in the success block is an &lt;code&gt;NSDictionary&lt;/code&gt; instance. The benefit of working with the &lt;code&gt;AFJSONHTTPRequestOperation&lt;/code&gt; class, which we registered in &lt;code&gt;initWithBaseURL:&lt;/code&gt;, is that it accepts the JSON response and automatically creates an object from the response data, a dictionary in this example.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Querying the Forecast API&lt;/h2&gt;&lt;h3&gt;Step 1: Amend &lt;code&gt;setLocation:&lt;/code&gt;&lt;/h3&gt;&lt;p&gt;Armed with the &lt;code&gt;MTForecastClient&lt;/code&gt; class, it is time to query the Forecast API and fetch the weather data for the currently selected location. The most suitable place to do this is in the &lt;code&gt;setLocation:&lt;/code&gt; method of the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class. Amend the &lt;code&gt;setLocation:&lt;/code&gt; method as shown below. As you can see, all we do is invoke &lt;code&gt;fetchWeatherData&lt;/code&gt;, another helper method.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)setLocation:(NSDictionary *)location {
    if (_location != location) {
        _location = location;
        // Update User Defaults
        NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
        [ud setObject:location forKey:MTRainUserDefaultsLocation];
        [ud synchronize];
        // Post Notification
        NSNotification *notification1 = [NSNotification notificationWithName:MTRainLocationDidChangeNotification object:self userInfo:location];
        [[NSNotificationCenter defaultCenter] postNotification:notification1];
        // Update View
        [self updateView];
        // Request Location
        [self fetchWeatherData];
    }
}
&lt;/pre&gt;&lt;p&gt;Have you ever wondered why I use so many helper methods in my code? The reason is simple. By wrapping functionality in helper methods, it is very easy to reuse code in various places of a project. The main benefit, however, is that it helps battle code duplication. Code duplication is something you should always try to avoid as much as possible. Another advantage of using helper methods is that it makes your code much more readable. By creating methods that do one thing and providing a well chosen method name, it is easier to quickly read and process your code.&lt;/p&gt;&lt;h3&gt;Step 2: Sending the Request&lt;/h3&gt;&lt;p&gt;It is time to put the &lt;code&gt;SVProgressHUD&lt;/code&gt; library to use. I really like this library because it is so simple to use without cluttering the project's code base. Take a look at the implementation of &lt;code&gt;fetchWeatherData&lt;/code&gt; below. We start by showing the progress HUD and then pass a structure (&lt;code&gt;CLLocationCoordinate2D&lt;/code&gt;) to the convenience method we created earlier, &lt;code&gt;requestWeatherForCoordinate:completion:&lt;/code&gt;. In the completion block, we hide the progress HUD and log the response to the console.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)fetchWeatherData {
    // Show Progress HUD
    [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];
    // Query Forecast API
    double lat = [[_location objectForKey:MTLocationKeyLatitude] doubleValue];
    double lng = [[_location objectForKey:MTLocationKeyLongitude] doubleValue];
    [[MTForecastClient sharedClient] requestWeatherForCoordinate:CLLocationCoordinate2DMake(lat, lng) completion:^(BOOL success, NSDictionary *response) {
        // Dismiss Progress HUD
        [SVProgressHUD dismiss];
        NSLog(@&amp;quot;Response &amp;gt; %@&amp;quot;, response);
    }];
}
&lt;/pre&gt;&lt;p&gt;Before you build and run your application, import the header file of the &lt;code&gt;MTForecastClient&lt;/code&gt; class in &lt;strong&gt;MTWeatherViewController.m&lt;/strong&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTWeatherViewController.h&amp;quot;
#import &amp;quot;MTForecastClient.h&amp;quot;
@interface MTWeatherViewController () &amp;lt;CLLocationManagerDelegate&amp;gt; {
    BOOL _locationFound;
}
@property (strong, nonatomic) NSDictionary *location;
@property (strong, nonatomic) CLLocationManager *locationManager;
@end
&lt;/pre&gt;&lt;p&gt;What happens when the device is not connected to the web? Have you thought about that scenario? In terms of user experience, it is good practice to notify the user when the application is unable to request data from the Forecast API. Let me show how to do this with the AFNetworking library.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Reachability&lt;/h2&gt;&lt;p&gt;There are a number of libraries that provide this functionality, but we will stick with AFNetworking. Apple also provides &lt;a
href="http://developer.apple.com/library/ios/#samplecode/Reachability/Introduction/Intro.html"&gt;sample code&lt;/a&gt;, but it is a bit outdated and doesn't support ARC.&lt;/p&gt;&lt;p&gt;AFNetworking has truly embraced blocks, which is definitely one of the reasons that this library has become so popular. Monitoring for reachability changes is as simple as passing a block to &lt;code&gt;setReachabilityStatusChangeBlock:&lt;/code&gt;, another method of the &lt;code&gt;AFHTTPClient&lt;/code&gt; class. The block is executed every time the reachability status changes and it accepts a single argument of type &lt;code&gt;AFNetworkReachabilityStatus&lt;/code&gt;. Take a look at the updated &lt;code&gt;initWithBaseURL:&lt;/code&gt; method of the &lt;code&gt;MTForecastClient&lt;/code&gt; class.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithBaseURL:(NSURL *)url {
    self = [super initWithBaseURL:url];
    if (self) {
        // Accept HTTP Header
        [self setDefaultHeader:@&amp;quot;Accept&amp;quot; value:@&amp;quot;application/json&amp;quot;];
        // Register HTTP Operation Class
        [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
        // Reachability
        __weak typeof(self)weakSelf = self;
        [self setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
            [[NSNotificationCenter defaultCenter] postNotificationName:MTRainReachabilityStatusDidChangeNotification object:weakSelf];
        }];
    }
    return self;
}
&lt;/pre&gt;&lt;p&gt;To avoid a retain cycle, we pass a weak reference to the singleton object in the block that we pass to &lt;code&gt;setReachabilityStatusChangeBlock:&lt;/code&gt;. Even if you use ARC in your projects, you still need to be aware of subtle memory issues like this. The name of the notification that we post is another string constant declared in &lt;strong&gt;MTConstants.h/.m&lt;/strong&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
extern NSString * const MTRainReachabilityStatusDidChangeNotification;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
NSString * const MTRainReachabilityStatusDidChangeNotification = @&amp;quot;com.mobileTuts.MTRainReachabilityStatusDidChangeNotification&amp;quot;;
&lt;/pre&gt;&lt;p&gt;The reason for posting a notification in the reachability status change block is to make it easier for other parts of the application to update when the device's reachability changes. To make sure that the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class is notified of reachability changes, instances of the class are added as an observer for the notifications sent by the Forecast client as shown below.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialize Location Manager
        self.locationManager = [[CLLocationManager alloc] init];
        // Configure Location Manager
        [self.locationManager setDelegate:self];
        [self.locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer];
        // Add Observer
        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc addObserver:self selector:@selector(reachabilityStatusDidChange:) name:MTRainReachabilityStatusDidChangeNotification object:nil];
    }
    return self;
}
&lt;/pre&gt;&lt;p&gt;This also means that we need to remove the instance as an observer in the &lt;code&gt;dealloc&lt;/code&gt; method. This is a detail that is often overlooked.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)dealloc {
    // Remove Observer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
&lt;/pre&gt;&lt;p&gt;The implementation of &lt;code&gt;reachabilityStatusDidChange:&lt;/code&gt; is pretty basic at the moment. We will update its implementation once we create the application's user interface.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)reachabilityStatusDidChange:(NSNotification *)notification {
    MTForecastClient *forecastClient = [notification object];
    NSLog(@&amp;quot;Reachability Status &amp;gt; %i&amp;quot;, forecastClient.networkReachabilityStatus);
}
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Refreshing Data&lt;/h2&gt;&lt;p&gt;Before we wrap this post up, I want to add two additional features, (1) fetching weather data whenever the application becomes active and (2) adding the ability to manually refresh weather data. We could implement a timer that fetches fresh data every hour or so, but this is not necessary for a weather application in my opinion. Most users will launch the application, take a look at the weather and put the application in the background. It is therefore only necessary to fetch fresh data when the user launches the application. This means that we need to listen for &lt;code&gt;UIApplicationDidBecomeActiveNotification&lt;/code&gt; notifications in the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class. As we did for monitoring reachability changes, we add instances of the class as observers of notifications of type &lt;code&gt;UIApplicationDidBecomeActiveNotification&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialize Location Manager
        self.locationManager = [[CLLocationManager alloc] init];
        // Configure Location Manager
        [self.locationManager setDelegate:self];
        [self.locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer];
        // Add Observer
        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
        [nc addObserver:self selector:@selector(reachabilityStatusDidChange:) name:MTRainReachabilityStatusDidChangeNotification object:nil];
    }
    return self;
}
&lt;/pre&gt;&lt;p&gt;In &lt;code&gt;applicationDidBecomeActive:&lt;/code&gt;, we verify that &lt;code&gt;location&lt;/code&gt; is set (not &lt;code&gt;nil&lt;/code&gt;) because this won't always be true. If the location is valid, we fetch the weather data.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)applicationDidBecomeActive:(NSNotification *)notification {
    if (self.location) {
        [self fetchWeatherData];
    }
}
&lt;/pre&gt;&lt;p&gt;I have also amended &lt;code&gt;fetchWeatherData&lt;/code&gt; to only query the Forecast API if the device is connected to the web.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)fetchWeatherData {
    if ([[MTForecastClient sharedClient] networkReachabilityStatus] == AFNetworkReachabilityStatusNotReachable) return;
    // Show Progress HUD
    [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];
    // Query Forecast API
    double lat = [[_location objectForKey:MTLocationKeyLatitude] doubleValue];
    double lng = [[_location objectForKey:MTLocationKeyLongitude] doubleValue];
    [[MTForecastClient sharedClient] requestWeatherForCoordinate:CLLocationCoordinate2DMake(lat, lng) completion:^(BOOL success, NSDictionary *response) {
        // Dismiss Progress HUD
        [SVProgressHUD dismiss];
        // NSLog(@&amp;quot;Response &amp;gt; %@&amp;quot;, response);
    }];
}
&lt;/pre&gt;&lt;p&gt;Let's add a button to the weather view controller that the user can tap to manually refresh the weather data. Create an outlet in &lt;strong&gt;MTWeatherViewController.h&lt;/strong&gt; and create a &lt;code&gt;refresh:&lt;/code&gt; action in &lt;strong&gt;MTWeatherViewController.m&lt;/strong&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
#import &amp;quot;MTLocationsViewController.h&amp;quot;
@interface MTWeatherViewController : UIViewController &amp;lt;MTLocationsViewControllerDelegate&amp;gt;
@property (weak, nonatomic) IBOutlet UILabel *labelLocation;
@property (weak, nonatomic) IBOutlet UIButton *buttonRefresh;
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (IBAction)refresh:(id)sender {
    if (self.location) {
        [self fetchWeatherData];
    }
}
&lt;/pre&gt;&lt;p&gt;Open &lt;strong&gt;MTWeatherViewController.xib&lt;/strong&gt;, add a button to the view controller's view with a title of &lt;strong&gt;Refresh&lt;/strong&gt;, and connect the outlet and action with the button (figure 3). The reason for creating an outlet for the button is to be able to disable it when no network connection is available. For this to work, we need to update the &lt;code&gt;reachabilityStatusDidChange:&lt;/code&gt; method as shown below.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130518-3.png" alt="Create a Weather App with Forecast – Forecast Integration - Adding a Refresh Button " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 3: Adding a Refresh Button&lt;/figcaption&gt; &lt;/figure&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)reachabilityStatusDidChange:(NSNotification *)notification {
    MTForecastClient *forecastClient = [notification object];
    NSLog(@&amp;quot;Reachability Status &amp;gt; %i&amp;quot;, forecastClient.networkReachabilityStatus);
    // Update Refresh Button
    self.buttonRefresh.enabled = (forecastClient.networkReachabilityStatus != AFNetworkReachabilityStatusNotReachable);
}
&lt;/pre&gt;&lt;p&gt;It isn't necessary to temporarily disable the refresh button when a request is being processed in &lt;code&gt;fetchWeatherData&lt;/code&gt; because the progress HUD adds a layer on top of the view controller's view that prevents the user from tapping the button more than once. Build and run the application to test everything out.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Bonus: Removing Locations&lt;/h2&gt;&lt;p&gt;A reader asked me how to delete locations from the list so I am including it here for the sake of completeness. The first thing that we need to do is tell the table view which rows are editable by implementing &lt;code&gt;tableView:canEditRowAtIndexPath:&lt;/code&gt; of the &lt;code&gt;UITableViewDataSource&lt;/code&gt; protocol. This method returns &lt;code&gt;YES&lt;/code&gt; if the row at &lt;code&gt;indexPath&lt;/code&gt; is editable and &lt;code&gt;NO&lt;/code&gt; if it is not. The implementation is simple as you can see below. Every row is editable except for the first row and the currently selected location.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        return NO;
    }
    // Fetch Location
    NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)];
    return ![self isCurrentLocation:location];
}
&lt;/pre&gt;&lt;p&gt;To check whether &lt;code&gt;location&lt;/code&gt; is the current location, we use another helper method, &lt;code&gt;isCurrentLocation:&lt;/code&gt;, in which we fetch the current location and compare the locations coordinates. It would have been better (and easier) if we had assigned a unique identifier to each location stored in the user defaults database. Not only would it make it easier to compare locations, but it would also allow us to store the current location's unique identifier in the user defaults database and look it up in the array of locations. The problem with the current implementation is that locations with the exact same coordinates cannot be distinguished from one another.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (BOOL)isCurrentLocation:(NSDictionary *)location {
    // Fetch Current Location
    NSDictionary *currentLocation = [[NSUserDefaults standardUserDefaults] objectForKey:MTRainUserDefaultsLocation];
    if ([location[MTLocationKeyLatitude] doubleValue] == [currentLocation[MTLocationKeyLatitude] doubleValue] &amp;amp;&amp;amp;
        [location[MTLocationKeyLongitude] doubleValue] == [currentLocation[MTLocationKeyLongitude] doubleValue]) {
        return YES;
    }
    return NO;
}
&lt;/pre&gt;&lt;p&gt;When the user taps the delete button of a table view row, the table view data source is sent a &lt;code&gt;tableView:commitEditingStyle:forRowAtIndexPath:&lt;/code&gt; message. In this method, we need to (1) update the data source, (2) save the changes to the user defaults database, and (3) update the table view. If &lt;code&gt;editingStyle&lt;/code&gt; is equal to &lt;code&gt;UITableViewCellEditingStyleDelete&lt;/code&gt;, we remove the location from the &lt;code&gt;locations&lt;/code&gt; array and store the updated array in the user defaults database. We also delete the row from the table view to reflect the change in the data source.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Update Locations
        [self.locations removeObjectAtIndex:(indexPath.row - 1)];
        // Update User Defaults
        [[NSUserDefaults standardUserDefaults] setObject:self.locations forKey:MTRainUserDefaultsLocations];
        // Update Table View
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
    }
}
&lt;/pre&gt;&lt;p&gt;To toggle the table view's editing style, we need to add an edit button to the user interface. Create an outlet for the button in &lt;strong&gt;MTLocationsViewController.h&lt;/strong&gt; and an action named &lt;code&gt;editLocations:&lt;/code&gt; in &lt;strong&gt;MTLocationsViewController.m&lt;/strong&gt;. In &lt;code&gt;editLocations:&lt;/code&gt;, we toggle the table view's editing style.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
@protocol MTLocationsViewControllerDelegate;
@interface MTLocationsViewController : UIViewController &amp;lt;UITableViewDataSource, UITableViewDelegate&amp;gt;
@property (weak, nonatomic) id&amp;lt;MTLocationsViewControllerDelegate&amp;gt; delegate;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *editButton;
@end
@protocol MTLocationsViewControllerDelegate &amp;lt;NSObject&amp;gt;
- (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller;
- (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location;
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (IBAction)editLocations:(id)sender {
    [self.tableView setEditing:![self.tableView isEditing] animated:YES];
}
&lt;/pre&gt;&lt;p&gt;Open &lt;strong&gt;MTLocationsViewController.xib&lt;/strong&gt;, add a navigation bar to the view controller's view, and add an edit button to the navigation bar. Connect the edit button with the outlet and action that we created a moment ago.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130518-4.png" alt="Create a Weather App with Forecast – Forecast Integration - Adding an Edit Button " /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 4: Adding an Edit Button&lt;/figcaption&gt;&lt;hr
/&gt;&lt;p&gt;You may be wondering why we created an outlet for the edit button. The reason is that we need to be able to change the title of the edit button from &lt;strong&gt;Edit&lt;/strong&gt; to &lt;strong&gt;Done&lt;/strong&gt;, and vice versa, whenever the editing style of the table view changes. In addition, when the user deletes the last location (except for the current location) in the table view, it would be nice to automatically toggle the table view's editing style. These features are not hard to implement which is why I leave them up to you as an exercise. If you run into problems or have questions, feel free to leave a comment in the comments below this article.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;We have successfully integrated the Forecast API in our weather application. In the next tutorial, we will implement focus on the user interface and the design of the application.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/TjrrRLNQudk" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-api-integration/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-api-integration/</feedburner:origLink></item> <item><title>Reading NFC Tags with Android</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/fAK8stCZ8eI/</link> <comments>http://mobile.tutsplus.com/tutorials/android/reading-nfc-tags-with-android/#comments</comments> <pubDate>Thu, 16 May 2013 17:32:40 +0000</pubDate> <dc:creator>Ralf Wondratschek</dc:creator> <category><![CDATA[Android SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17278</guid> <description>&lt;p&gt;Are you curious about what NFC is and how it can be integrated into your own Android applications? This tutorial will quickly introduce you to the topic before diving in and teaching you how to build a simple NFC reader app!&lt;br
/&gt;&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;What is NFC?&lt;/h2&gt;&lt;p&gt;NFC is the abbreviation for &lt;em&gt;Near Field Communication&lt;/em&gt;. It is the international standard for contactless exchange of data. In contrast to a large range of other technologies, such as wireless LAN and Bluetooth, the maximum distance of two devices is 10cm. The development of the standard started in 2002 by NXP Semiconductors and Sony. The &lt;a
href="http://www.nfc-forum.org/home/"&gt;NFC Forum&lt;/a&gt;, a consortium of over 170 companies and members, which included Mastercard, NXP, Nokia, Samsung, Intel, and Google, has been designing new specifications since 2004.&lt;/p&gt;&lt;p&gt;There are various possibilities for NFC use with mobile devices; for example, paperless tickets, access controls, cashless payments, and car keys. With the help of NFC tags you can control your phone and change settings. Data can be exchanged simply by holding two devices next to each other.&lt;/p&gt;&lt;p&gt;In this tutorial I want to explain how to implement NFC with the Android SDK, which pitfalls exist, and what to keep in mind. We will create an app step by step, which can read the content of NFC tags supporting NDEF.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;NFC Technologies&lt;/h2&gt;&lt;p&gt;There are a variety of NFC tags that can be read with a smartphone. The spectrum ranges from simple stickers and key rings to complex cards with integrated cryptographic hardware. Tags also differ in their chip technology. The most important is NDEF, which is supported by most tags. In addidition, Mifare should be mentioned as it is the most used contactless chip technology worldwide. Some tags can be read and written, while others are read-only or encrypted.&lt;/p&gt;&lt;p&gt;Only the NFC Data Exchange Format (NDEF) is discussed in this tutorial.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Reading-NFC-Tags-with-Android_2.jpg" alt="girogo-card" /&gt;&lt;br
/&gt; &lt;fig
caption="X-ray view of a girogo-card" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;/p&gt;&lt;/hr&gt;&lt;h2&gt;Adding NFC Support in an App&lt;/h2&gt;&lt;p&gt;We start with a new project and a blank activity. It is important to select a minimum SDK version of level 10, because NFC is only supported after Android 2.3.3. Remember to choose your own package name. I&amp;#8217;ve chosen &lt;em&gt;net.vrallev.android.nfc.demo&lt;/em&gt;, because vrallev.net is the domain of my website and the other part refers to the topic of this application.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
	&amp;lt;uses-sdk
		android:minSdkVersion=&amp;quot;10&amp;quot;
        android:targetSdkVersion=&amp;quot;17&amp;quot; /&amp;gt;
	&lt;/pre&gt;&lt;p&gt;The default layout generated by Eclipse is almost sufficient for us. I&amp;#8217;ve only added an ID to the TextView and changed the text.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
	&amp;lt;TextView
        android:id=&amp;quot;@+id/textView_explanation&amp;quot;
        android:layout_width=&amp;quot;wrap_content&amp;quot;
        android:layout_height=&amp;quot;wrap_content&amp;quot;
        android:text=&amp;quot;@string/explanation&amp;quot; /&amp;gt;
	&lt;/pre&gt;&lt;p&gt;To get access to the NFC hardware, you have to apply for permission in the manifest. If the app won&amp;#8217;t work without NFC, you can specify the condition with the uses-feature tag. If NFC is required, the app can&amp;#8217;t be installed on devices without it and Google Play will only display your app to users who own a NFC device.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
	&amp;lt;uses-permission android:name=&amp;quot;android.permission.NFC&amp;quot; /&amp;gt;
    &amp;lt;uses-feature
        android:name=&amp;quot;android.hardware.nfc&amp;quot;
        android:required=&amp;quot;true&amp;quot; /&amp;gt;
	&lt;/pre&gt;&lt;p&gt;The MainActivity should only consist of the onCreate() method. You can interact with the hardware via the NfcAdapter class. It is important to find out whether the NfcAdapter is null. In this case, the Android device does not support NFC.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
	package net.vrallev.android.nfc.demo;
	import android.app.Activity;
	import android.nfc.NfcAdapter;
	import android.os.Bundle;
	import android.widget.TextView;
	import android.widget.Toast;
	/**
	 * Activity for reading data from an NDEF Tag.
	 *
	 * @author Ralf Wondratschek
	 *
	 */
	public class MainActivity extends Activity {
		public static final String TAG = &amp;quot;NfcDemo&amp;quot;;
		private TextView mTextView;
		private NfcAdapter mNfcAdapter;
		@Override
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.activity_main);
			mTextView = (TextView) findViewById(R.id.textView_explanation);
			mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
			if (mNfcAdapter == null) {
				// Stop here, we definitely need NFC
				Toast.makeText(this, &amp;quot;This device doesn't support NFC.&amp;quot;, Toast.LENGTH_LONG).show();
				finish();
				return;
			}
			if (!mNfcAdapter.isEnabled()) {
				mTextView.setText(&amp;quot;NFC is disabled.&amp;quot;);
			} else {
				mTextView.setText(R.string.explanation);
			}
			handleIntent(getIntent());
		}
		private void handleIntent(Intent intent) {
			// TODO: handle Intent
		}
	}
	&lt;/pre&gt;&lt;p&gt;If we start our app now, we can see the text whether NFC is enabled or disabled.&lt;/p&gt;&lt;/hr&gt;&lt;h2&gt;How to Filter for NFC Tags&lt;/h2&gt;&lt;p&gt;We have our sample app and want to receive a notification from the system when we attach an NFC tag to the device. As usual, Android uses its Intent system to deliver tags to the apps. If multiple apps can handle the Intent, the activity chooser gets displayed and the user can decide which app will be opened. Opening URLs or sharing information is handled the same way.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;NFC Intent Filter&lt;/h2&gt;&lt;p&gt;There are three different filters for tags:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;ACTION_NDEF_DISCOVERED&lt;/li&gt;&lt;li&gt;ACTION_TECH_DISCOVERED&lt;/li&gt;&lt;li&gt;ACTION_TAG_DISCOVERED&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The list is sorted from the highest to the lowest priority.&lt;/p&gt;&lt;p&gt;Now what happens when a tag is attached to the smartphone? If the system detects a tag with NDEF support, an Intent is triggered. An &lt;em&gt;ACTION_TECH_DISCOVERED&lt;/em&gt; Intent is triggered if no Activity from any app is registered for the NDEF Intent or if the tag does not support NDEF. If again no app is found for the Intent or the chip technology could not be detected, then a &lt;em&gt;ACTION_TAG_DISCOVERED&lt;/em&gt; Intent is fired. The following graphic shows the process:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Reading-NFC-Tags-with-Android_3.png" alt="nfc tag dispatch" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;In summary this means that each app needs to filter after the Intent with the highest priority. In our case, this is the NDEF Intent. We implement the &lt;em&gt;ACTION_TECH_DISCOVERED&lt;/em&gt; Intent first to highlight the difference between priorities.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;Tech Discovered Intent&lt;/h2&gt;&lt;p&gt;We must specify the technology we are interested in. For this purpose, we create a subfolder called &lt;em&gt;xml&lt;/em&gt; in the &lt;em&gt;res&lt;/em&gt; folder. In this folder we create the file &lt;em&gt;nfc_tech_filter.xml&lt;/em&gt;, in which we specify the technologies.&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
	&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
	&amp;lt;resources xmlns:xliff=&amp;quot;urn:oasis:names:tc:xliff:document:1.2&amp;quot;&amp;gt;
	    &amp;lt;tech-list&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.Ndef&amp;lt;/tech&amp;gt;
	        &amp;lt;!-- class name --&amp;gt;
	    &amp;lt;/tech-list&amp;gt;
	&amp;lt;/resources&amp;gt;
	&amp;lt;!--
	&amp;lt;resources xmlns:xliff=&amp;quot;urn:oasis:names:tc:xliff:document:1.2&amp;quot;&amp;gt;
	    &amp;lt;tech-list&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.IsoDep&amp;lt;/tech&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.NfcA&amp;lt;/tech&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.NfcB&amp;lt;/tech&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.NfcF&amp;lt;/tech&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.NfcV&amp;lt;/tech&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.Ndef&amp;lt;/tech&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.NdefFormatable&amp;lt;/tech&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.MifareClassic&amp;lt;/tech&amp;gt;
	        &amp;lt;tech&amp;gt;android.nfc.tech.MifareUltralight&amp;lt;/tech&amp;gt;
	    &amp;lt;/tech-list&amp;gt;
	&amp;lt;/resources&amp;gt;
	--&amp;gt;
	&lt;/pre&gt;&lt;p&gt;Now we must create an IntentFilter in the manifest, and the app will be started when we attach a tag.&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
	&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
	&amp;lt;activity
		android:name=&amp;quot;net.vrallev.android.nfc.demo.MainActivity&amp;quot;
        android:label=&amp;quot;@string/app_name&amp;quot; &amp;gt;
        &amp;lt;intent-filter&amp;gt;
            &amp;lt;action android:name=&amp;quot;android.intent.action.MAIN&amp;quot; /&amp;gt;
            &amp;lt;category android:name=&amp;quot;android.intent.category.LAUNCHER&amp;quot; /&amp;gt;
        &amp;lt;/intent-filter&amp;gt;
        &amp;lt;intent-filter&amp;gt;
            &amp;lt;action android:name=&amp;quot;android.nfc.action.TECH_DISCOVERED&amp;quot; /&amp;gt;
        &amp;lt;/intent-filter&amp;gt;
        &amp;lt;meta-data
            android:name=&amp;quot;android.nfc.action.TECH_DISCOVERED&amp;quot;
            android:resource=&amp;quot;@xml/nfc_tech_filter&amp;quot; /&amp;gt;
    &amp;lt;/activity&amp;gt;
	&lt;/pre&gt;&lt;p&gt;If no other app is registered for this Intent, our Activity will start immediately. On my device, however, other apps are installed, so the activity chooser gets displayed.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Reading-NFC-Tags-with-Android_4.png" alt="screenshot" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr/&gt;&lt;h2&gt;NDEF Discovered Intent&lt;/h2&gt;&lt;p&gt;As I mentioned before, the Tech Discovered Intent has the second highest priority. However, since our app will support only NDEF, we can use the NDEF Discovered Intent instead, which has a higher priority. We can delete the technology list again and replace the IntentFilter with the following one.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
	&amp;lt;intent-filter&amp;gt;
		&amp;lt;action android:name=&amp;quot;android.nfc.action.NDEF_DISCOVERED&amp;quot; /&amp;gt;
		&amp;lt;category android:name=&amp;quot;android.intent.category.DEFAULT&amp;quot; /&amp;gt;
		&amp;lt;data android:mimeType=&amp;quot;text/plain&amp;quot; /&amp;gt;
	&amp;lt;/intent-filter&amp;gt;
	&lt;/pre&gt;&lt;p&gt;When we attach the tag now, the app will be started like before. There is a difference for me, however. The activity chooser does not appear and the app starts immediately, because the NDEF Intent has a higher priority and the other apps only registered for the lower priorities. That&amp;#8217;s exactly what we want.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;Foreground Dispatch&lt;/h2&gt;&lt;p&gt;Note that one problem remains. When our app is already opened and we attach the tag again, the app is opened a second time instead of delivering the tag directly. This is not our intended behavior. You can bypass the problem by using a Foreground Dispatch.&lt;/p&gt;&lt;p&gt;Instead of the system having distributed the Intent, you can register your Activity to receive the tag directly. This is important for a particular workflow, where it makes no sense to open another app.&lt;/p&gt;&lt;p&gt;I&amp;#8217;ve inserted the explanations at the appropriate places in the code.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
	package net.vrallev.android.nfc.demo;
	import android.app.Activity;
	import android.app.PendingIntent;
	import android.content.Intent;
	import android.content.IntentFilter;
	import android.content.IntentFilter.MalformedMimeTypeException;
	import android.nfc.NfcAdapter;
	import android.os.Bundle;
	import android.widget.TextView;
	import android.widget.Toast;
	/**
	 * Activity for reading data from an NDEF Tag.
	 *
	 * @author Ralf Wondratschek
	 *
	 */
	public class MainActivity extends Activity {
		public static final String MIME_TEXT_PLAIN = &amp;quot;text/plain&amp;quot;;
		public static final String TAG = &amp;quot;NfcDemo&amp;quot;;
		private TextView mTextView;
		private NfcAdapter mNfcAdapter;
		@Override
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.activity_main);
			mTextView = (TextView) findViewById(R.id.textView_explanation);
			mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
			if (mNfcAdapter == null) {
				// Stop here, we definitely need NFC
				Toast.makeText(this, &amp;quot;This device doesn't support NFC.&amp;quot;, Toast.LENGTH_LONG).show();
				finish();
				return;
			}
			if (!mNfcAdapter.isEnabled()) {
				mTextView.setText(&amp;quot;NFC is disabled.&amp;quot;);
			} else {
				mTextView.setText(R.string.explanation);
			}
			handleIntent(getIntent());
		}
		@Override
		protected void onResume() {
			super.onResume();
			/**
			 * It's important, that the activity is in the foreground (resumed). Otherwise
			 * an IllegalStateException is thrown.
			 */
			setupForegroundDispatch(this, mNfcAdapter);
		}
		@Override
		protected void onPause() {
			/**
			 * Call this before onPause, otherwise an IllegalArgumentException is thrown as well.
			 */
			stopForegroundDispatch(this, mNfcAdapter);
			super.onPause();
		}
		@Override
		protected void onNewIntent(Intent intent) {
			/**
			 * This method gets called, when a new Intent gets associated with the current activity instance.
			 * Instead of creating a new activity, onNewIntent will be called. For more information have a look
			 * at the documentation.
			 *
			 * In our case this method gets called, when the user attaches a Tag to the device.
			 */
			handleIntent(intent);
		}
		private void handleIntent(Intent intent) {
			// TODO: handle Intent
		}
		/**
		 * @param activity The corresponding {@link Activity} requesting the foreground dispatch.
		 * @param adapter The {@link NfcAdapter} used for the foreground dispatch.
		 */
		public static void setupForegroundDispatch(final Activity activity, NfcAdapter adapter) {
			final Intent intent = new Intent(activity.getApplicationContext(), activity.getClass());
			intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
			final PendingIntent pendingIntent = PendingIntent.getActivity(activity.getApplicationContext(), 0, intent, 0);
			IntentFilter[] filters = new IntentFilter[1];
			String[][] techList = new String[][]{};
			// Notice that this is the same filter as in our manifest.
			filters[0] = new IntentFilter();
			filters[0].addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
			filters[0].addCategory(Intent.CATEGORY_DEFAULT);
			try {
				filters[0].addDataType(MIME_TEXT_PLAIN);
			} catch (MalformedMimeTypeException e) {
				throw new RuntimeException(&amp;quot;Check your mime type.&amp;quot;);
			}
			adapter.enableForegroundDispatch(activity, pendingIntent, filters, techList);
		}
		/**
		 * @param activity The corresponding {@link BaseActivity} requesting to stop the foreground dispatch.
		 * @param adapter The {@link NfcAdapter} used for the foreground dispatch.
		 */
		public static void stopForegroundDispatch(final Activity activity, NfcAdapter adapter) {
			adapter.disableForegroundDispatch(activity);
		}
	}
	&lt;/pre&gt;&lt;p&gt;Now, when you attach a tag and our app is already opened, onNewIntent is called and no new Activity is created.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;Reading Data From an NDEF Tag&lt;/h2&gt;&lt;p&gt;The last step is to read the data from the tag. The explanations are inserted at the appropriate places in the code once again. The NdefReaderTask is a private inner class.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
	package net.vrallev.android.nfc.demo;
	import java.io.UnsupportedEncodingException;
	import java.util.Arrays;
	import android.app.Activity;
	import android.app.PendingIntent;
	import android.content.Intent;
	import android.content.IntentFilter;
	import android.content.IntentFilter.MalformedMimeTypeException;
	import android.nfc.NdefMessage;
	import android.nfc.NdefRecord;
	import android.nfc.NfcAdapter;
	import android.nfc.Tag;
	import android.nfc.tech.Ndef;
	import android.os.AsyncTask;
	import android.os.Bundle;
	import android.util.Log;
	import android.widget.TextView;
	import android.widget.Toast;
	/*
	 * ... other code parts
	 */
	private void handleIntent(Intent intent) {
		String action = intent.getAction();
		if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
			String type = intent.getType();
			if (MIME_TEXT_PLAIN.equals(type)) {
				Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
				new NdefReaderTask().execute(tag);
			} else {
				Log.d(TAG, &amp;quot;Wrong mime type: &amp;quot; + type);
			}
		} else if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
			// In case we would still use the Tech Discovered Intent
			Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
			String[] techList = tag.getTechList();
			String searchedTech = Ndef.class.getName();
			for (String tech : techList) {
				if (searchedTech.equals(tech)) {
					new NdefReaderTask().execute(tag);
					break;
				}
			}
		}
	}
	&lt;/pre&gt;&lt;pre class="brush: jscript; title: ;"&gt;
	/**
	 * Background task for reading the data. Do not block the UI thread while reading.
	 *
	 * @author Ralf Wondratschek
	 *
	 */
	private class NdefReaderTask extends AsyncTask&amp;lt;Tag, Void, String&amp;gt; {
		@Override
		protected String doInBackground(Tag... params) {
			Tag tag = params[0];
			Ndef ndef = Ndef.get(tag);
			if (ndef == null) {
				// NDEF is not supported by this Tag.
				return null;
			}
			NdefMessage ndefMessage = ndef.getCachedNdefMessage();
			NdefRecord[] records = ndefMessage.getRecords();
			for (NdefRecord ndefRecord : records) {
				if (ndefRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN &amp;amp;&amp;amp; Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
					try {
						return readText(ndefRecord);
					} catch (UnsupportedEncodingException e) {
						Log.e(TAG, &amp;quot;Unsupported Encoding&amp;quot;, e);
					}
				}
			}
			return null;
		}
		private String readText(NdefRecord record) throws UnsupportedEncodingException {
			/*
			 * See NFC forum specification for &amp;quot;Text Record Type Definition&amp;quot; at 3.2.1
			 *
			 * http://www.nfc-forum.org/specs/
			 *
			 * bit_7 defines encoding
			 * bit_6 reserved for future use, must be 0
			 * bit_5..0 length of IANA language code
			 */
			byte[] payload = record.getPayload();
			// Get the Text Encoding
			String textEncoding = ((payload[0] &amp;amp; 128) == 0) ? &amp;quot;UTF-8&amp;quot; : &amp;quot;UTF-16&amp;quot;;
			// Get the Language Code
			int languageCodeLength = payload[0] &amp;amp; 0063;
			// String languageCode = new String(payload, 1, languageCodeLength, &amp;quot;US-ASCII&amp;quot;);
			// e.g. &amp;quot;en&amp;quot;
			// Get the Text
			return new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
		}
		@Override
		protected void onPostExecute(String result) {
			if (result != null) {
				mTextView.setText(&amp;quot;Read content: &amp;quot; + result);
			}
		}
	}
	&lt;/pre&gt;&lt;p&gt;The app now successfully reads the content.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Reading-NFC-Tags-with-Android_5.png" alt="screen" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr/&gt;&lt;h2&gt;Useful Apps&lt;/h2&gt;&lt;p&gt;To check whether data is read and written properly, I personally like to use following apps:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="https://play.google.com/store/apps/details?id=at.mroland.android.apps.nfctaginfo"&gt;NFC TagInfo&lt;/a&gt; by NFC Research Lab for reading data&lt;/li&gt;&lt;li&gt;&lt;a
href="https://play.google.com/store/apps/details?id=com.nxp.taginfolite"&gt;TagInfo&lt;/a&gt; by NXP SEMICONDUCTORS for reading data&lt;/li&gt;&lt;li&gt;&lt;a
href="https://play.google.com/store/apps/details?id=com.nxp.nfc.tagwriter"&gt;TagWriter&lt;/a&gt; by NXP SEMICONDUCTORS for writing data&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;In this tutorial I have shown you how the data from a NDEF tag can be extracted. You could expand the example to other mime types and chip technologies; a feature to write data would be useful as well. The first step to work with NFC was made. However, the Android SDK offers much more possibilities, such as an easy exchange of data (called Android Beam).&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;About the Author&lt;/h2&gt;&lt;p&gt;Ralf Wondratschek is a computer science student from Germany. In addition to his studies, Ralf works as a freelancer in the field of mobile computing. In the last few years he has worked with Java, XML, HTML, JSP, JSF, Eclipse, Google App Engine, and of course Android. He has published two Android apps to date &lt;a
href="https://market.android.com/search?q=de.vrallev&amp;#038;so=1&amp;#038;c=apps"&gt;which can be found here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You can find out more about the author’s work on his homepage &lt;a
href="http://www.vrallev.net"&gt;vrallev.net&lt;/a&gt;.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;Sources&lt;/h2&gt;&lt;p&gt;&lt;a
href="http://www.nfc-forum.org/home/n-mark.jpg"&gt;http://www.nfc-forum.org/home/n-mark.jpg&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a
href="http://commons.wikimedia.org/wiki/File%3A%C3%9Cberlagert.jpg"&gt;http://commons.wikimedia.org/wiki/File%3A%C3%9Cberlagert.jpg&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a
href="http://developer.android.com/images/nfc_tag_dispatch.png"&gt;http://developer.android.com/images/nfc_tag_dispatch.png&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/fAK8stCZ8eI" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/android/reading-nfc-tags-with-android/feed/</wfw:commentRss> <slash:comments>1</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/android/reading-nfc-tags-with-android/</feedburner:origLink></item> <item><title>Connecting to an External Database With NuSOAP</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/123d4EOG3g8/</link> <comments>http://mobile.tutsplus.com/tutorials/windows/connecting-to-an-external-database-with-nusoap/#comments</comments> <pubDate>Wed, 15 May 2013 17:57:52 +0000</pubDate> <dc:creator>Tomasz Wójcik</dc:creator> <category><![CDATA[Windows Phone]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=15832</guid> <description>&lt;p&gt;Many mobile applications use external databases that are located remotely on the Internet. In the following tutorial, we will create a simple database, connect to it, and receive or send data from this source. To do this we will use a Windows Phone 7 Silverlight based application and a NuSOAP web service. Let&amp;#8217;s begin!&lt;br
/&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1. &lt;/span&gt;Install the Software&lt;/h2&gt;&lt;p&gt;Before we start we need to install the following programs:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="http://bangowinphone75sdk.codeplex.com/"&gt;Windows Phone 7.5 SDK&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://silverlight.codeplex.com/releases/view/78435"&gt;Silverlight 5 Toolkit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;PHP Library to run the web service (&lt;a
href="http://sourceforge.net/projects/nusoap/"&gt;NuSOAP&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Obviously, we will also need some sort of web hosting where we can create a database. Most of the free hosting options will be enough for us, but they may have some limitations which I will discuss later on in this tutorial.&lt;/p&gt;&lt;p&gt;We also need an FTP client. In this tutorial I will use a &lt;a
href="https://addons.mozilla.org/en-US/firefox/addon/fireftp/"&gt;FireFTP&lt;/a&gt; add-on to Mozilla Firefox. But you can use anything you want.&lt;/p&gt;&lt;p&gt;When all the programs are installed, we can continue.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2. &lt;/span&gt;Creating an External Database&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;To begin, check that the hosting uses phpMyAdmin because I use it in the examples. But if you choose to use something else all the commands should be similar.&lt;/p&gt;&lt;p&gt;First we need to create a simple database, in our case it will contain only one table and three attributes:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;ID&lt;/b&gt; &amp;#8211; this value identifies the record. It must be set as an &lt;b&gt;autoincrement&lt;/b&gt; field.&lt;/li&gt;&lt;li&gt;&lt;b&gt;FirstName&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;LastName&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The table name is &lt;b&gt;MyUsers&lt;/b&gt;.&lt;/p&gt;&lt;p&gt;To do this just click &lt;b&gt;&amp;#8220;create table&amp;#8221;&lt;/b&gt;:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_1.png" /&gt;&lt;/figure&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;After that, fill in the cells as shown in this screenshot:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_2.png" /&gt;&lt;/figure&gt;&lt;p&gt;The table structure should now look like this:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_3.png" /&gt;&lt;/figure&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt;At this step we must note a few important points:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Host address&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;As I wrote earlier, free hostings have limits, one of these is to possibly connect only from &lt;b&gt;localhost&lt;/b&gt;, remember that!&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt; Database user&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Our username to log into the database:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Database password&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Database name&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3. &lt;/span&gt;NuSOAP Server &amp;#8211; Starting Web Service&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;Starting our web service is very simple:&lt;/p&gt;&lt;p&gt;First, we must copy some files to the ftp server. I recommend a ftp server because it is directly connected to our hosting because of the &lt;b&gt;localhost&lt;/b&gt; issue.&lt;/p&gt;&lt;p&gt;Once we&amp;#8217;re connected, we need to copy the nusoap.php file which was downloaded earlier. We also require a file that will contain specific functions written by us that is necessary for our application; I called it &lt;b&gt;MyService.php&lt;/b&gt;.&lt;/p&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;After we copy the files, our &lt;b&gt;FTP&lt;/b&gt; root directory should look like the image below:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_4.png" /&gt;&lt;/figure&gt;&lt;p&gt;Now open the &lt;b&gt;MyService.php&lt;/b&gt; file and write into it:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
&amp;lt;?php
// Pull in the NuSOAP
code require_once('nusoap.php');
// Create the server instance
$server = new soap_server();
// Initialize WSDL support
(MyService is name of our service)
$server-----&amp;gt;configureWSDL('MyService', 'urn:MyService');
        // Character encoding
        $server-&amp;gt;soap_defencoding = 'utf-8';
        //-------------------------------------------------
        //Registrations of our functions
        //-------------------------------------------------
        //Our web service functions will be here.
        //-------------------------------------------------
        $HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
        $server-&amp;gt;service($HTTP_RAW_POST_DATA);
?&amp;gt;
    &lt;/pre&gt;&lt;p&gt;The most important points are explained in the upper comments to code.&lt;/p&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt;From now on our service should work. We can check this by typing in the web browser:&lt;/p&gt;&lt;p&gt;&lt;b&gt;http://www.ourdomain.com/MyService.php&lt;/b&gt;&lt;/p&gt;&lt;p&gt;If all went well you should see something like this:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_5.png" /&gt;&lt;/figure&gt;&lt;p&gt;After we successfully started the web service, we can go to the next step.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4. &lt;/span&gt;Writing Web Service Functions&lt;/h2&gt;&lt;p&gt;In our service we need two functions:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The first function adds data to the online database.&lt;/li&gt;&lt;li&gt;The second function receives data from it.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;Let&amp;#8217;s open &lt;b&gt;MyService.php&lt;/b&gt;. We need to register the new function, to do this we should type:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
    $server-&amp;gt;register(
        'InsertData',   //Name of function
      	array('FirstName' =&amp;gt; 'xsd:string', 'LastName' =&amp;gt; 'xsd:string'), //Input Values
      	array('return' =&amp;gt;'xsd:boolean'), //Output Values
    	  'urn:MyServicewsdl',  //Namespace
        'urn:MyServicewsdl#InsertData',  //SoapAction
        'rpc',       //style
        'literal',   //can be encoded but it doesn't work with silverlight
        'Some_comments_about_function'
    );
    &lt;/pre&gt;&lt;p&gt;Remember that it needs to be placed before the body function and after the server directives.&lt;/p&gt;&lt;p&gt;Here is some code explanation:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
      'FirstName' =&amp;gt; 'xsd:string'
    &lt;/pre&gt;&lt;p&gt;&lt;b&gt;&amp;#8220;FirstName&amp;#8221;&lt;/b&gt; is the name of variable, &lt;b&gt;&amp;#8220;string&amp;#8221;&lt;/b&gt; is the type of variable (i.e. it can be &lt;b&gt;int, longint, boolean&lt;/b&gt;, etc.).&lt;/p&gt;&lt;p&gt;When the function registers, we need to write the body of it. Below is the code and explanation:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
    function InsertData($FirstName, $LastName) {
    	$connect = mysql_pconnect(&amp;quot;Host&amp;quot;,&amp;quot;UserName&amp;quot;,&amp;quot;UserPassword&amp;quot;));
    	if ($connect) {
    		if(mysql_select_db(&amp;quot;DatabaseName&amp;quot;, $connect)) {
          mysql_query(&amp;quot;INSERT INTO MyUser SET FirstName='$FirstName', LastName='$LastName'&amp;quot;);
    			return true;
    		}
    	}
    	return false;
    }
    &lt;/pre&gt;&lt;pre class="brush: php; title: ;"&gt;
          InsertData($FirstName, $LastName)
        &lt;/pre&gt;&lt;p&gt;Here&amp;#8217;s the name of the function and its attributes. They must be the same as in the registration section.&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
          $connect = mysql_pconnect(&amp;quot;Host&amp;quot;,&amp;quot;UserName&amp;quot;,&amp;quot;UserPassword&amp;quot;);
        &lt;/pre&gt;&lt;p&gt;Here we can insert the data we noticed when we created the database.&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
          if(mysql_select_db(&amp;quot;DatabaseName&amp;quot;, $connect)) {
        &lt;/pre&gt;&lt;p&gt;And also here.&lt;/p&gt;&lt;p&gt;After that it is a simple MySQL query that adds data to our database:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
          mysql_query(&amp;quot;INSERT INTO MyUser SET FistName='$FirstName', LastName='$LastName'&amp;quot;);
        &lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;Now it&amp;#8217;s time to write the second function. The structure will be similar to the first.&lt;/p&gt;&lt;p&gt;Here is the code of method registration:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
      $server-&amp;gt;register(
          'GetData',
        	array('ID' =&amp;gt; 'xsd:int'),
        	array('return' =&amp;gt;'xsd:string'),
      	  'urn:MyServicewsdl',
          'urn:MyServicewsdl#GetData',
          'rpc',
          'literal',
          'Some comments about function 2'
      );
       &lt;/pre&gt;&lt;p&gt;The main differences are in the Input/Output values section (changed types of variables).&lt;/p&gt;&lt;p&gt;Here&amp;#8217;s the body function code:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
       function GetData($ID) {
      	$connect = mysql_pconnect(&amp;quot;Host&amp;quot;,&amp;quot;UserName&amp;quot;,&amp;quot;UserPassword&amp;quot;);
      	if ($connect) {
      		if(mysql_select_db(&amp;quot;DatabaseName&amp;quot;, $connect)) {
            $sql = &amp;quot;SELECT FirstName, LastName FROM MyUser WHERE ID = '$ID'&amp;quot;;
      			$result = mysql_fetch_array(mysql_query($sql));
      			return $result['FirstName'].&amp;quot;-&amp;quot;.$result['LastName'];
      		}
      	}
      	return false;
      }
      &lt;/pre&gt;&lt;p&gt;Here is a little code explanation:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
         return $result['FirstName'].&amp;quot;-&amp;quot;.$result['LastName'];
&lt;/pre&gt;&lt;p&gt;This line states what must return to the Windows Phone application.&lt;/p&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt;After writing all the functions the MyService.php file should look like this:&lt;/p&gt;&lt;pre class="brush: php; title: ;"&gt;
&amp;lt;?php
// Pull in the NuSOAP code
require_once('nusoap.php');
// Create the server instance
$server = new soap_server();
// Initialize WSDL support
configureWSDL('MyService', 'urn:MyService');
                // Character encoding
                $server-&amp;gt;soap_defencoding = 'utf-8';
                //-------------------------------------------------
                //Register InsertData function
                $server-&amp;gt;register(
                        'InsertData',
                      	array('FirstName' =&amp;gt; 'xsd:string', 'LastName' =&amp;gt; 'xsd:string'),
                      	array('return' =&amp;gt;'xsd:boolean'),
                    	  'urn:MyServicewsdl',
                        'urn:MyServicewsdl#InsertData',
                        'rpc',
                        'literal',
                        'Some comments about function'
                    );
                //Register GetData function
                $server-&amp;gt;register(
                        'GetData',
                      	array('ID' =&amp;gt; 'xsd:int'),
                      	array('return' =&amp;gt;'xsd:string'),
                    	  'urn:MyServicewsdl',
                        'urn:MyServicewsdl#GetData',
                        'rpc',
                        'literal',
                        'Some comments about function 2'
                    );
                //-------------------------------------------------
                //Body InsterData function
                function InsertData($FirstName, $LastName) {
                	$connect = mysql_pconnect(&amp;quot;Host&amp;quot;,&amp;quot;UserName&amp;quot;,&amp;quot;UserPassword&amp;quot;);
                	if ($connect) {
                		if(mysql_select_db(&amp;quot;DatabaseName&amp;quot;, $connect)) {
                      mysql_query(&amp;quot;INSERT INTO MyUser SET FirstName='$FirstName', LastName='$LastName'&amp;quot;);
                			return true;
                		}
                	}
                	return false;
                }
                //Body GetData function
                function GetData($ID) {
                	$connect = mysql_pconnect(&amp;quot;Host&amp;quot;,&amp;quot;UserName&amp;quot;,&amp;quot;UserPassword&amp;quot;);
                	if ($connect) {
                		if(mysql_select_db(&amp;quot;DatabaseName&amp;quot;, $connect)) {
                      $sql = &amp;quot;SELECT FirstName, LastName FROM MyUser WHERE ID = '$ID'&amp;quot;;
                			$result = mysql_fetch_array(mysql_query($sql));
                			return $result['FirstName'].&amp;quot;-&amp;quot;.$result['LastName'];
                		}
                	}
                	return false;
                }
                //-------------------------------------------------
                $HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : '';
                $server-&amp;gt;service($HTTP_RAW_POST_DATA);
        ?&amp;gt;
      &lt;/pre&gt;&lt;p&gt;To validate the functions we can again type &lt;b&gt;http://www.ourdomain.com/MyService.php&lt;/b&gt; in the browser. Now the site should look a little bit different, but similar to this:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_6.png" width="359" height="250" /&gt;&lt;/figure&gt;&lt;p&gt;Now we&amp;#8217;re ready to go to next step.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;5. &lt;/span&gt;Creating a Simple Layout for a Windows Phone Application&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;Firstly, we must create a Windows Phone app. Let&amp;#8217;s run Microsoft Visual Studio for Windows Phone 2010. After Visual Studio starts, click &amp;#8220;File&amp;#8221; then &amp;#8220;New Project&amp;#8221;. You should see a dialog window like in the screenshot below:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_7.png" /&gt;&lt;/figure&gt;&lt;p&gt;Our app will use Silverlight, so we must check this template. We can also change the project name, like localisations, etc. In my case, the project name is &amp;#8220;MyApplication&amp;#8221;. After you have done this, click the OK button.&lt;/p&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;At this point we must note what we need in our app. We need:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Two text boxes for sending data to the database (First Name, Last Name)&lt;/li&gt;&lt;li&gt;One text box to receive the data (ID)&lt;/li&gt;&lt;li&gt;Two buttons to approve our actions&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Adding objects (such as buttons) to our application is easy, just drag it from &amp;#8220;ToolBox&amp;#8221; and drop it onto preview of the app. Keep in mind that you have a free hand in setting your own layout.&lt;/p&gt;&lt;p&gt;This is how it looks on my app:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_8.png" /&gt;&lt;/figure&gt;&lt;p&gt;Another important aspect is the names of the elements used in Visual Studio (they&amp;#8217;re used later in code).&lt;/p&gt;&lt;p&gt;To change it, just click on element. Then in properties you can see text like &amp;#8220;Textbox1&amp;#8243;, click on it, and change it to something that you can remember, that is crucial. I used these names for my elements:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&amp;#8220;FirstNameBox&amp;#8221;, &amp;#8220;LastNameBox&amp;#8221;, and &amp;#8220;IdBox&amp;#8221; for text boxes&lt;/li&gt;&lt;li&gt;&amp;#8220;SendBTN&amp;#8221; and &amp;#8220;ReadBTN&amp;#8221; for buttons&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;That&amp;#8217;s all we need to do in this step, we can move on.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;6. &lt;/span&gt;Connecting to Service&lt;/h2&gt;&lt;p&gt;To connect to the web service we must right click on &amp;#8220;Reference&amp;#8221; in &amp;#8220;Solution Explorer&amp;#8221; dialog and select &amp;#8220;Add Service Reference&amp;#8230;&amp;#8221;&lt;/p&gt;&lt;p&gt;Here how this looks:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_9.png" /&gt;&lt;/figure&gt;&lt;p&gt;After that a new window will appear. In it we must write the address of our web service and the name of namespace.&lt;/p&gt;&lt;p&gt;In our case an address will be created, like on this scheme: http://www.ourdomain.com/MyService.php?wsdl.&lt;/p&gt;&lt;p&gt;After entering an address and clicking &amp;#8220;Go&amp;#8221; you should see something like this:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_10.png" /&gt;&lt;/figure&gt;&lt;p&gt;If you see the operations called &amp;#8220;GetData&amp;#8221; and &amp;#8220;InsertData&amp;#8221; that means the connection was successfully created! Remember to type namespace, in my case it is &amp;#8220;MyService&amp;#8221;. Now click OK.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;7. &lt;/span&gt;Writing Windows Phone Functions&lt;/h2&gt;&lt;p&gt;We&amp;#8217;re almost at the end of this tutorial; we only need to write two simple functions.&lt;/p&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;The first function will be behind the &amp;#8220;Send&amp;#8221; button, so double click it. Now we must add at the top of the file a &amp;#8220;using&amp;#8221; directive of our service:&lt;/p&gt;&lt;pre class="brush: csharp; title: ;"&gt;
      using MyApplication.MyService;
    &lt;/pre&gt;&lt;p&gt;Let&amp;#8217;s look at the send function behind the &amp;#8220;Send&amp;#8221; button, now it is empty:&lt;/p&gt;&lt;pre class="brush: csharp; title: ;"&gt;
        private void SendBTN_Click(object sender, RoutedEventArgs e)
        {
        }
    &lt;/pre&gt;&lt;p&gt;Our complete function should look like this:&lt;/p&gt;&lt;pre class="brush: csharp; title: ;"&gt;
        private void SendBTN_Click(object sender, RoutedEventArgs e)
        {
            //Creating new proxy object of our service
            MyServicePortTypeClient send = new MyServicePortTypeClient();
            send.InsertDataCompleted += new EventHandler&amp;lt;InsertDataCompletedEventArgs&amp;gt;(send_InsertDataCompleted);
            //Calling method, as a parameters we type text contained in FirstNameBox and LastNameBox
            //This data will be sent to web service and later to database
            send.InsertDataAsync(FirstNameBox.Text, LastNameBox.Text);
        }
        void send_InsertDataCompleted(object sender, InsertDataCompletedEventArgs e)
        {
            //If our server return true, that means we're added data to database...
            if (e.Result)
                MessageBox.Show(&amp;quot;Successfully added!&amp;quot;);
            //...if return false we aren't.
            else
                MessageBox.Show(&amp;quot;Some problems occured!&amp;quot;);
        }
    &lt;/pre&gt;&lt;p&gt;The most important points are explained in the code comments, but we must be aware of the following:&lt;/p&gt;&lt;p&gt;Method &amp;#8220;send_InsertDataCompleted&amp;#8221; executes when we get an answer from the server. Also this function is not in the &amp;#8220;SendBTN&amp;#8221; object, it is outside.&lt;/p&gt;&lt;p&gt;Now it&amp;#8217;s time to test our work! Start to debug and fill out the boxes with some data. Here I have entered John as a first name and Doe as a last name, then I clicked Send:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_11.png" /&gt;&lt;/figure&gt;&lt;p&gt;Let&amp;#8217;s see how the database looks now:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_12.png" /&gt;&lt;/figure&gt;&lt;p&gt;Yes, the new record with ID = 1 has appeared and everything is going well.&lt;/p&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;Now we&amp;#8217;ve reached the final function for receiving. It is similar to the previous method. Double click on the &amp;#8220;Read&amp;#8221; button and copy the code:&lt;/p&gt;&lt;pre class="brush: csharp; title: ;"&gt;
      private void ReadBTN_Click(object sender, RoutedEventArgs e)
        {
            //Creating new proxy object of our service
            MyServicePortTypeClient read = new MyServicePortTypeClient();
            read.GetDataCompleted += new EventHandler&amp;lt;GetDataCompletedEventArgs&amp;gt;(read_GetDataCompleted);
            //Calling method, as a parameters we type text contained in IdTextBox
            //but we must change text type of string to integer (ID in web service have integer type)
            read.GetDataAsync(Convert.ToInt32(IdBox.Text));
        }
        void read_GetDataCompleted(object sender, GetDataCompletedEventArgs e)
        {
            MessageBox.Show(e.Result);
        }
    &lt;/pre&gt;&lt;p&gt;This is the same process as before, &amp;#8220;read_GetDataCompleted&amp;#8221; executes after getting data from the database. In this method we&amp;#8217;ll use a message box to show our result, i.e. first and last name. There is one more step to do; we need to change the type of text in IdBox from string to integer because the variable called ID in the web service has an integer type. To do this I used a function called &lt;b&gt;&amp;#8220;Convert.ToIn32()&amp;#8221;&lt;/b&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;8. &lt;/span&gt;Testing&lt;/h2&gt;&lt;p&gt;Now we can see if this works. Enter ID into &amp;#8220;IdTextBox&amp;#8221;. I entered &amp;#8220;1&amp;#8243;, then clicked the &amp;#8220;Read&amp;#8221; button.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;img
alt="" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/andrea-morris/WP7WebService_13.png" /&gt;&lt;/figure&gt;&lt;p&gt;Everything is working! Our application is now complete!&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;In this tutorial we created a database using a Windows Phone 7 Silverlight based application and NuSOAP web service. This database is helpful to receive or send data. External databases are important because they are used by many mobile applications.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/123d4EOG3g8" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/windows/connecting-to-an-external-database-with-nusoap/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/windows/connecting-to-an-external-database-with-nusoap/</feedburner:origLink></item> <item><title>Create a Weather App with Forecast – Project Setup</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/WlKCi2IWoag/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-project-setup/#comments</comments> <pubDate>Mon, 13 May 2013 19:52:08 +0000</pubDate> <dc:creator>Bart Jacobs</dc:creator> <category><![CDATA[iOS SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17014</guid> <description>&lt;p&gt;In March of this year, the company behind &lt;a
href="http://darkskyapp.com"&gt;Dark Sky&lt;/a&gt; and &lt;a
href="http://forecast.io"&gt;Forecast.io&lt;/a&gt; introduced Forecast. Forecast is a simple weather API that provides both short- and longterm weather data. In this series, I will show you how to create a beautiful weather application for iOS powered by Forecast.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Introduction&lt;/h2&gt;&lt;p&gt;&lt;a
href="http://blog.forecast.io/announcing-forecast/"&gt;Earlier this year&lt;/a&gt;, the Dark Sky Company introduced &lt;a
href="https://developer.forecast.io"&gt;Forecast&lt;/a&gt;, a simple yet powerful weather API that provides short and longterm weather predictions. In this series we will create an iOS application that is powered by the Forecast API. Forecast is free for up to a thousand API calls per day, so feel free to &lt;a
href="https://developer.forecast.io/register"&gt;sign up&lt;/a&gt; for a developer account and follow along with me.&lt;/p&gt;&lt;p&gt;Even though a number of open source wrappers for the Forecast API are available, in this series we will use the AFNetworking library to query the Forecast API. In the first part of this series, we will create the project&amp;#8217;s foundation and implement a basic user interface. Even though our application is simple in scope, it will support multiple locations and that is what we will focus on in this article.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Project Setup&lt;/h2&gt;&lt;h3&gt;Step 1: Creating the Project&lt;/h3&gt;&lt;p&gt;Fire up Xcode and create a new project based on the &lt;strong&gt;Empty Application&lt;/strong&gt; template (figure 1). Name the application &lt;strong&gt;Rain&lt;/strong&gt; and enable &lt;strong&gt;Automatic Reference Counting&lt;/strong&gt; (figure 2).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130510-1.png" alt="Creating a Weather App for iOS with Forecast.io: Part 1 - Setting Up the Project " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 1: Setting Up the Project&lt;/figcaption&gt; &lt;/figure&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130510-2.png" alt="Creating a Weather App for iOS with Forecast.io: Part 1 - Configuring the Project " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 2: Configuring the Project&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 2: Adding Libraries&lt;/h3&gt;&lt;p&gt;For this project, we will be using three open source libraries, &lt;a
href="https://github.com/samvermette/SVProgressHUD"&gt;SVProgressHUD&lt;/a&gt; created by &lt;a
href="https://github.com/samvermette"&gt;Sam Vermette&lt;/a&gt;, &lt;a
href="https://github.com/AFNetworking/AFNetworking"&gt;AFNetworking&lt;/a&gt; created by &lt;a
href="https://github.com/mattt"&gt;Mattt Thompson&lt;/a&gt;, and &lt;a
href="https://github.com/Inferis/ViewDeck"&gt;ViewDeck&lt;/a&gt; created by &lt;a
href="https://github.com/Inferis"&gt;Tom Adriaenssen&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Since I am an avid fan of &lt;a
href="http://cocoapods.org"&gt;CocoaPods&lt;/a&gt;, I will be using it to install and manage the libraries of our project. If you are not familiar with CocoaPods, then I recommend visiting the website of &lt;a
href="http://cocoapods.org"&gt;CocoaPods&lt;/a&gt; or reading my &lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/streamlining-cocoa-development-with-cocoapods/"&gt;introduction to CocoaPods&lt;/a&gt;. You can also manually add each library to your project if you prefer to not use CocoaPods.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Close your project&lt;/strong&gt;, browse to the project&amp;#8217;s root, and create a file named &lt;strong&gt;Podfile&lt;/strong&gt;. Open &lt;strong&gt;Podfile&lt;/strong&gt; in your favorite text editor and replace its contents with the snippet below. In the project&amp;#8217;s pod file, we specify the platform, deployment target, and the pods we want to include in the project.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
platform :ios, '6.0'
pod 'ViewDeck', '~&amp;gt; 2.2.11'
pod 'AFNetworking', '~&amp;gt; 1.2.1'
pod 'SVProgressHUD', '~&amp;gt; 0.9.0'
&lt;/pre&gt;&lt;p&gt;Open the &lt;strong&gt;Terminal&lt;/strong&gt; application, browse to the project&amp;#8217;s root, and install the libraries by executing &lt;code&gt;pod install&lt;/code&gt;. In addition to installing the three pods that we specified in the project&amp;#8217;s pod file, CocoaPods has already created an Xcode workspace for us. Open the new workspace by executing the &lt;code&gt;open Rain.xcworkspace&lt;/code&gt; command from the command line.&lt;/p&gt;&lt;h3&gt;Step 3: Adding Dependencies&lt;/h3&gt;&lt;p&gt;Before we can continue, we need to link our project against a handful of frameworks. The AFNetworking library depends on the &lt;strong&gt;Mobile Core Services&lt;/strong&gt; and &lt;strong&gt;System Configuration&lt;/strong&gt; frameworks and the ViewDeck library makes use of the &lt;strong&gt;Quartz Core&lt;/strong&gt; framework. Select the project from the &lt;strong&gt;Project Navigator&lt;/strong&gt; on the left, select the &lt;strong&gt;Rain&lt;/strong&gt; target in the list of targets, open the &lt;strong&gt;Build Phases&lt;/strong&gt; tab at the top, and expand the &lt;strong&gt;Link Binary With Libraries&lt;/strong&gt; drawer. Click the plus button to link your project against the aforementioned frameworks. We will be using the &lt;strong&gt;Core Location&lt;/strong&gt; framework a bit later in this article so now is good time to link your project against that framework as well (figure 3).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130510-3.png" alt="Creating a Weather App for iOS with Forecast.io: Part 1 - Linking the Project Against a Handful of Frameworks" /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 3: Linking the Project Against a Handful of Frameworks&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 4: Edit the Precompiled Header File&lt;/h3&gt;&lt;p&gt;Before we start implementing the basic structure of our weather application, it is a good idea to edit the precompiled header file of our project. Add an import statement for each of the frameworks we added to our project a moment ago and do the same for the AFNetworking, SVProgressHUD, and ViewDeck libraries.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;Availability.h&amp;gt;
#ifndef __IPHONE_3_0
#warning &amp;quot;This project uses features only available in iOS SDK 3.0 and later.&amp;quot;
#endif
#ifdef __OBJC__
    #import &amp;lt;UIKit/UIKit.h&amp;gt;
    #import &amp;lt;Foundation/Foundation.h&amp;gt;
    #import &amp;lt;QuartzCore/QuartzCore.h&amp;gt;
    #import &amp;lt;CoreLocation/CoreLocation.h&amp;gt;
    #import &amp;lt;MobileCoreServices/MobileCoreServices.h&amp;gt;
    #import &amp;lt;SystemConfiguration/SystemConfiguration.h&amp;gt;
    #import &amp;quot;AFNetworking.h&amp;quot;
    #import &amp;quot;SVProgressHUD.h&amp;quot;
    #import &amp;quot;IIViewDeckController.h&amp;quot;
#endif
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Laying the Foundation&lt;/h2&gt;&lt;p&gt;The concept and structure of the application is simple. The application manages three views, (1) a view in the center showing the current weather for a particular location, a view on the right showing the weather for the next few days, and a view on the left with a list of locations. The basic structure will make more sense once we&amp;#8217;ve implemented it. To create this structure, we make use of the terrific &lt;a
href="https://github.com/Inferis/ViewDeck"&gt;ViewDeck library&lt;/a&gt;, created and maintained by &lt;a
href="https://github.com/Inferis"&gt;Tom Adriaenssen&lt;/a&gt;. The ViewDeck library is one of the most powerful implementations of the sliding view design pattern originally introduced in Facebook for iOS.&lt;/p&gt;&lt;h3&gt;Step 1: View Controllers&lt;/h3&gt;&lt;p&gt;Before we put the ViewDeck library to use, we need to create the view controller classes that will manage the three views I mentioned in the previous paragraph. Create three &lt;code&gt;UIViewController&lt;/code&gt; subclasses named &lt;code&gt;MTWeatherViewController&lt;/code&gt;, &lt;code&gt;MTForecastViewController&lt;/code&gt;, and &lt;code&gt;MTLocationsViewController&lt;/code&gt;, respectively (figure 4). Don&amp;#8217;t forget to create a user interface or XIB file for each class (figure 4).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130510-4.png" alt="Creating a Weather App for iOS with Forecast.io: Part 1 - Creating the Three Main View Controller Classes" /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 4: Creating the Three Main View Controller Classes&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 2: Creating a View Deck Controller&lt;/h3&gt;&lt;p&gt;Open &lt;strong&gt;MTAppDelegate.m&lt;/strong&gt; and import the header file the three &lt;code&gt;UIViewController&lt;/code&gt; subclasses. Add a class extension and create a property of type &lt;code&gt;IIViewDeckController&lt;/code&gt; and name it &lt;code&gt;viewDeckController&lt;/code&gt;. The reason for this will become clear in a moment.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTAppDelegate.h&amp;quot;
#import &amp;quot;MTWeatherViewController.h&amp;quot;
#import &amp;quot;MTForecastViewController.h&amp;quot;
#import &amp;quot;MTLocationsViewController.h&amp;quot;
@interface MTAppDelegate ()
@property (strong, nonatomic) IIViewDeckController *viewDeckController;
@end
&lt;/pre&gt;&lt;p&gt;In &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt;, we start by creating an instance of each of the three &lt;code&gt;UIViewController&lt;/code&gt; subclasses. We then initialize an instance of the &lt;code&gt;IIViewDeckController&lt;/code&gt; class and pass the view controller objects as arguments to &lt;code&gt;initWithCenterViewController:leftViewController:rightViewController:&lt;/code&gt;. As the initializer indicates, the view deck controller that we create manages a center, left, and right view controller. The rest of the implementation of &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt; should be familiar to you. We initialize the application window and set the view deck controller as its root view controller.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Initialize View Controllers
    MTLocationsViewController *leftViewController = [[MTLocationsViewController alloc] initWithNibName:@&amp;quot;MTLocationsViewController&amp;quot; bundle:nil];
    MTForecastViewController *rightViewController = [[MTForecastViewController alloc] initWithNibName:@&amp;quot;MTForecastViewController&amp;quot; bundle:nil];
    MTWeatherViewController *centerViewController = [[MTWeatherViewController alloc] initWithNibName:@&amp;quot;MTWeatherViewController&amp;quot; bundle:nil];
    // Initialize View Deck Controller
    self.viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:centerViewController leftViewController:leftViewController rightViewController:rightViewController];
    // Initialize Window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Configure Window
    [self.window setRootViewController:self.viewDeckController];
    [self.window makeKeyAndVisible];
    return YES;
}
&lt;/pre&gt;&lt;p&gt;Build and run the application in the iOS Simulator or on a physical device to see the ViewDeck library in action. Even though the views of the view controllers are empty, the fundamental application structure is ready.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Adding Locations&lt;/h2&gt;&lt;p&gt;As I mentioned in the introduction, in this tutorial we will also add the ability to add locations to the list of locations managed by the application. The &lt;code&gt;MTLocationsViewController&lt;/code&gt; class is in charge of managing the list of locations and presenting them in a table view. The user can add the current location to the list of locations by tapping the table view&amp;#8217;s first row, which will be labeled &amp;#8220;Add Current Location&amp;#8221;. Adding a new location with the Core Location framework is a responsibility of the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class as we will see in a few minutes.&lt;/p&gt;&lt;p&gt;This leaves us with a problem. How is the weather view controller notified when the user has tapped the first row of the locations view controller? Notification center? Delegation is a better choice in this context. Whenever I encounter the need for a one-way communication between two objects, I tend to choose for delegation in favor of notifications. A delegate protocol is much easier to wrap your head around and extending it is as simple as declaring another method.&lt;/p&gt;&lt;p&gt;Another option would be to pass a reference to the weather view controller to the locations view controller, but I don&amp;#8217;t like this type of tight coupling. Tight coupling makes code less reusable and it results in unnecessarily complex object hierarchies when the code base grows over time. Delegation is the right choice for this problem.&lt;/p&gt;&lt;h3&gt;Step 1: Declaring the Delegate Protocol&lt;/h3&gt;&lt;p&gt;Open &lt;strong&gt;MTLocationsViewController.h&lt;/strong&gt; and update the header file as shown below. We create a property for the view controller&amp;#8217;s delegate and we declare the &lt;code&gt;MTLocationsViewControllerDelegate&lt;/code&gt; protocol. The protocol defines two methods, (1) &lt;code&gt;controllerShouldAddCurrentLocation:&lt;/code&gt;, which is invoked when the first row in the view controller&amp;#8217;s table view is tapped, and (2) &lt;code&gt;controller:didSelectLocation:&lt;/code&gt;, which is invoked when the user select a location from the list of locations.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
@protocol MTLocationsViewControllerDelegate;
@interface MTLocationsViewController : UIViewController
@property (weak, nonatomic) id&amp;lt;MTLocationsViewControllerDelegate&amp;gt; delegate;
@end
@protocol MTLocationsViewControllerDelegate &amp;lt;NSObject&amp;gt;
- (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller;
- (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location;
@end
&lt;/pre&gt;&lt;h3&gt;Step 2: Adding the Table View&lt;/h3&gt;&lt;p&gt;Revisit &lt;strong&gt;MTLocationsViewController.h&lt;/strong&gt; one more time. Create an outlet for the view controller&amp;#8217;s table view and make sure to conform the &lt;code&gt;MTLocationsViewController&lt;/code&gt; class to the &lt;code&gt;UITableViewDataSource&lt;/code&gt; and &lt;code&gt;UITableViewDelegate&lt;/code&gt; protocols.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
@protocol MTLocationsViewControllerDelegate;
@interface MTLocationsViewController : UIViewController &amp;lt;UITableViewDataSource, UITableViewDelegate&amp;gt;
@property (weak, nonatomic) id&amp;lt;MTLocationsViewControllerDelegate&amp;gt; delegate;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end
@protocol MTLocationsViewControllerDelegate &amp;lt;NSObject&amp;gt;
- (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller;
- (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location;
@end
&lt;/pre&gt;&lt;p&gt;Open &lt;strong&gt;MTLocationsViewController.xib&lt;/strong&gt;, add a table view to the view controller&amp;#8217;s view, and set the table view&amp;#8217;s &lt;code&gt;dataSource&lt;/code&gt; and &lt;code&gt;delegate&lt;/code&gt; outlets to the &lt;strong&gt;File&amp;#8217;s Owner&lt;/strong&gt; object. Select the &lt;strong&gt;File&amp;#8217;s Owner&lt;/strong&gt; object and connect its &lt;code&gt;tableView&lt;/code&gt; outlet with the table view that we added to the view controller&amp;#8217;s view (figure 5).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130510-5.png" alt="Creating a Weather App for iOS with Forecast.io: Part 1 - Adding a Table View to List the Locations " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 5: Adding a Table View to List the Locations&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 3: Populating the Table View&lt;/h3&gt;&lt;p&gt;Before we implement the &lt;code&gt;UITableViewDataSource&lt;/code&gt; and &lt;code&gt;UITableViewDelegate&lt;/code&gt; protocols, we need to create a property that will serve as the table view&amp;#8217;s data source. Create a class extension at the top of &lt;strong&gt;MTLocationsViewController.m&lt;/strong&gt; and create a property named &lt;code&gt;locations&lt;/code&gt; of type &lt;code&gt;NSMutableArray&lt;/code&gt;. It will store the locations managed by our application.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTLocationsViewController.h&amp;quot;
@interface MTLocationsViewController ()
@property (strong, nonatomic) NSMutableArray *locations;
@end
&lt;/pre&gt;&lt;p&gt;Implementing the &lt;code&gt;UITableViewDataSource&lt;/code&gt; and the &lt;code&gt;UITableViewDelegate&lt;/code&gt; protocols is pretty straightforward. We start by declaring a static string constant for the cell reuse identifier. In the view controller&amp;#8217;s &lt;code&gt;viewDidLoad&lt;/code&gt; method we invoke &lt;code&gt;setupView&lt;/code&gt;, a helper method in which we configure the view controller&amp;#8217;s user interface. In &lt;code&gt;setupView&lt;/code&gt;, we tell the table view to use the &lt;code&gt;UITableViewCell&lt;/code&gt; class to instantiate new table view cells for the reuse identifier we declared earlier.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
static NSString *LocationCell = @&amp;quot;LocationCell&amp;quot;;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)viewDidLoad {
    [super viewDidLoad];
    // Setup View
    [self setupView];
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)setupView {
    // Register Class for Cell Reuse
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:LocationCell];
}
&lt;/pre&gt;&lt;p&gt;Implementing the &lt;code&gt;UITableViewDataSource&lt;/code&gt; and &lt;code&gt;UITableViewDelegate&lt;/code&gt; protocols is trivial as you can see below. Two implementation details require a bit explaining. We store each location as a dictionary with four keys, (1) city, (2) country, (3) latitude, and (4) longitude. With this in mind, the implementation of &lt;code&gt;configureCell:atIndexPath:&lt;/code&gt; should become a bit clearer. Note that &lt;code&gt;configureCell:atIndexPath:&lt;/code&gt; is nothing more than another helper method.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return ([self.locations count] + 1);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LocationCell forIndexPath:indexPath];
    // Configure Cell
    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        [cell.textLabel setText:@&amp;quot;Add Current Location&amp;quot;];
    } else {
        // Fetch Location
        NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)];
        // Configure Cell
        [cell.textLabel setText:[NSString stringWithFormat:@&amp;quot;%@, %@&amp;quot;, location[@&amp;quot;city&amp;quot;], location[@&amp;quot;country&amp;quot;]]];
    }
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return NO;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    return NO;
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    if (indexPath.row == 0) {
        // Notify Delegate
        [self.delegate controllerShouldAddCurrentLocation:self];
    } else {
        // Fetch Location
        NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)];
        // Notify Delegate
        [self.delegate controller:self didSelectLocation:location];
    }
    // Show Center View Controller
    [self.viewDeckController closeLeftViewAnimated:YES];
}
&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;tableView:didSelectRowAtIndexPath:&lt;/code&gt; also requires a short explanation. If the user taps the first row, labeled &lt;strong&gt;Add Current Location&lt;/strong&gt;, the delegate is notified that the current location should be added to the list of locations. If any other row in the table view is tapped, the corresponding location is passed as the second argument of &lt;code&gt;controller:didSelectLocation:&lt;/code&gt;, another delegate method of the &lt;code&gt;MTLocationsViewController&lt;/code&gt; delegate protocol. This informs the delegate that the application should set the new location as the application&amp;#8217;t default location and the weather data for that location should be fetched.&lt;/p&gt;&lt;p&gt;The last line of &lt;code&gt;tableView:didSelectRowAtIndexPath:&lt;/code&gt; is also worth mentioning. The &lt;code&gt;IIViewDeckController&lt;/code&gt; instance assigns itself to the view controllers it manages. The &lt;code&gt;viewDeckController&lt;/code&gt; property provides access to a view controller&amp;#8217;s view deck controller, which is convenient if you need to access the view controller&amp;#8217;s view deck. It works very much like the &lt;code&gt;navigationController&lt;/code&gt; property of a view controller instance. In the last line of &lt;code&gt;tableView:didSelectRowAtIndexPath:&lt;/code&gt;, we tell the view deck controller to close the left view, which means that the center view becomes visible again.&lt;/p&gt;&lt;h3&gt;Step 4: Keys and Constants&lt;/h3&gt;&lt;p&gt;Before we continue populating the locations table view, we need to pay attention to some best practices. We currently use string literals to access the values of the location dictionary. Even though this works perfectly fine, it is better and safer to use string constants for this purpose. To make all this easy and maintainable, we declare the string constants in a central location. Let me show you how this works.&lt;/p&gt;&lt;p&gt;Create a subclass of &lt;code&gt;NSObject&lt;/code&gt; and name it &lt;code&gt;MTConstants&lt;/code&gt;. Replace the contents of &lt;strong&gt;MTConstants.h&lt;/strong&gt; and &lt;strong&gt;MTConstants.m&lt;/strong&gt; with the snippets shown below. It should be clear that &lt;code&gt;MTConstants&lt;/code&gt; is not an Objective-C class. It is nothing more than a central place to store a set of constants specific to our project.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#pragma mark -
#pragma mark User Defaults
extern NSString * const MTRainUserDefaultsLocation;
extern NSString * const MTRainUserDefaultsLocations;
#pragma mark -
#pragma mark Notifications
extern NSString * const MTRainDidAddLocationNotification;
extern NSString * const MTRainLocationDidChangeNotification;
#pragma mark -
#pragma mark Location Keys
extern NSString * const MTLocationKeyCity;
extern NSString * const MTLocationKeyCountry;
extern NSString * const MTLocationKeyLatitude;
extern NSString * const MTLocationKeyLongitude;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTConstants.h&amp;quot;
#pragma mark -
#pragma mark User Defaults
NSString * const MTRainUserDefaultsLocation = @&amp;quot;location&amp;quot;;
NSString * const MTRainUserDefaultsLocations = @&amp;quot;locations&amp;quot;;
#pragma mark -
#pragma mark Notifications
NSString * const MTRainDidAddLocationNotification = @&amp;quot;com.mobileTuts.MTRainDidAddLocationNotification&amp;quot;;
NSString * const MTRainLocationDidChangeNotification = @&amp;quot;com.mobileTuts.MTRainLocationDidChangeNotification&amp;quot;;
#pragma mark -
#pragma mark Location Keys
NSString * const MTLocationKeyCity = @&amp;quot;city&amp;quot;;
NSString * const MTLocationKeyCountry = @&amp;quot;country&amp;quot;;
NSString * const MTLocationKeyLatitude = @&amp;quot;latitude&amp;quot;;
NSString * const MTLocationKeyLongitude = @&amp;quot;longitude&amp;quot;;
&lt;/pre&gt;&lt;p&gt;To make &lt;code&gt;MTConstants&lt;/code&gt; really useful, add an import statement for &lt;strong&gt;MTConstants.h&lt;/strong&gt; to your project&amp;#8217;s precompiled header file so the constants declared in &lt;code&gt;MTConstants&lt;/code&gt; are available throughout the project.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;Availability.h&amp;gt;
#ifndef __IPHONE_3_0
#warning &amp;quot;This project uses features only available in iOS SDK 3.0 and later.&amp;quot;
#endif
#ifdef __OBJC__
    #import &amp;lt;UIKit/UIKit.h&amp;gt;
    #import &amp;lt;Foundation/Foundation.h&amp;gt;
    #import &amp;lt;QuartzCore/QuartzCore.h&amp;gt;
    #import &amp;lt;CoreLocation/CoreLocation.h&amp;gt;
    #import &amp;lt;MobileCoreServices/MobileCoreServices.h&amp;gt;
    #import &amp;lt;SystemConfiguration/SystemConfiguration.h&amp;gt;
    #import &amp;quot;AFNetworking.h&amp;quot;
    #import &amp;quot;SVProgressHUD.h&amp;quot;
    #import &amp;quot;IIViewDeckController.h&amp;quot;
    #import &amp;quot;MTConstants.h&amp;quot;
#endif
&lt;/pre&gt;&lt;p&gt;We can now update &lt;code&gt;configureCell:atIndexPath:&lt;/code&gt; (&lt;strong&gt;MTLocationsViewController.m&lt;/strong&gt;) as shown below. Not only will this give use code completion and a very, very small performance gain, the true benefit of this best practice is that the compiler will warn us in case of typos. I&amp;#8217;m sure I don&amp;#8217;t have to tell you that typos are one of the most common causes of bugs in software development.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        [cell.textLabel setText:@&amp;quot;Add Current Location&amp;quot;];
    } else {
        // Fetch Location
        NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)];
        // Configure Cell
        [cell.textLabel setText:[NSString stringWithFormat:@&amp;quot;%@, %@&amp;quot;, location[MTLocationKeyCity], location[MTLocationKeyCountry]]];
    }
}
&lt;/pre&gt;&lt;p&gt;At the moment, the &lt;code&gt;locations&lt;/code&gt; property is empty and so will the table view. In &lt;code&gt;initWithNibName:bundle:&lt;/code&gt;, we invoke &lt;code&gt;loadLocations&lt;/code&gt;, a helper method that loads the array of locations. In &lt;code&gt;loadLocations&lt;/code&gt;, load the array of locations that is stored in the application&amp;#8217;s user defaults database. Note that we use another string constant that we declared in &lt;strong&gt;MTConstants.h&lt;/strong&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Load Locations
        [self loadLocations];
    }
    return self;
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)loadLocations {
    self.locations = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:MTRainUserDefaultsLocations]];
}
&lt;/pre&gt;&lt;h3&gt;Step 5: Delegate Assignment&lt;/h3&gt;&lt;p&gt;As I mentioned earlier, the &lt;code&gt;MTWeatherViewController&lt;/code&gt; instance will serve as the delegate of the locations view controller. Revisit &lt;strong&gt;MTAppDelegate.m&lt;/strong&gt; and update &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt; as shown below.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Initialize View Controllers
    MTLocationsViewController *leftViewController = [[MTLocationsViewController alloc] initWithNibName:@&amp;quot;MTLocationsViewController&amp;quot; bundle:nil];
    MTForecastViewController *rightViewController = [[MTForecastViewController alloc] initWithNibName:@&amp;quot;MTForecastViewController&amp;quot; bundle:nil];
    MTWeatherViewController *centerViewController = [[MTWeatherViewController alloc] initWithNibName:@&amp;quot;MTWeatherViewController&amp;quot; bundle:nil];
    // Configure Locations View Controller
    [leftViewController setDelegate:centerViewController];
    // Initialize View Deck Controller
    self.viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:centerViewController leftViewController:leftViewController rightViewController:rightViewController];
    // Initialize Window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Configure Window
    [self.window setRootViewController:self.viewDeckController];
    [self.window makeKeyAndVisible];
    return YES;
}
&lt;/pre&gt;&lt;p&gt;By making this change, a warning should immediately pop up telling you that &lt;code&gt;MTWeatherViewController&lt;/code&gt; does not conform to the &lt;code&gt;MTLocationsViewControllerDelegate&lt;/code&gt; protocol. The compiler is right so let&amp;#8217;s fix this.&lt;/p&gt;&lt;p&gt;Open &lt;strong&gt;MTWeatherViewController.h&lt;/strong&gt;, import the header file of &lt;code&gt;MTLocationsViewController&lt;/code&gt;, and conform &lt;code&gt;MTWeatherViewController&lt;/code&gt; to the &lt;code&gt;MTLocationsViewControllerDelegate&lt;/code&gt; protocol.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
#import &amp;quot;MTLocationsViewController.h&amp;quot;
@interface MTWeatherViewController : UIViewController &amp;lt;MTLocationsViewControllerDelegate&amp;gt;
@end
&lt;/pre&gt;&lt;p&gt;Wait. Another warning? We haven&amp;#8217;t implemented the two required methods of the delegate protocol yet hence the warning. Open &lt;strong&gt;MTWeatherViewController.m&lt;/strong&gt; and add a stub implementation for each of the delegate methods.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller {
    NSLog(@&amp;quot;%s&amp;quot;, __PRETTY_FUNCTION__);
}
- (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location {
    NSLog(@&amp;quot;%s&amp;quot;, __PRETTY_FUNCTION__);
}
&lt;/pre&gt;&lt;h3&gt;Step 6: Fetching the Current Location&lt;/h3&gt;&lt;p&gt;It is finally time to fetch the current location of the device. Add a class extension at the top of &lt;strong&gt;MTWeatherViewController.m&lt;/strong&gt; and declare two properties, (1) &lt;code&gt;location&lt;/code&gt; (&lt;code&gt;NSDictionary&lt;/code&gt;) to store the application&amp;#8217;s default location and (2) &lt;code&gt;locationManager&lt;/code&gt; (&lt;code&gt;CLLocationManager&lt;/code&gt;), which we will use to fetch the device&amp;#8217;s location. Conform the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class to the &lt;code&gt;CLLocationManagerDelegate&lt;/code&gt; protocol and declare an instance variable named &lt;code&gt;_locationFound&lt;/code&gt; of type &lt;code&gt;BOOL&lt;/code&gt;. The purpose of &lt;code&gt;_locationFound&lt;/code&gt; will become clear in a few minutes.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTWeatherViewController.h&amp;quot;
@interface MTWeatherViewController () &amp;lt;CLLocationManagerDelegate&amp;gt; {
    BOOL _locationFound;
}
@property (strong, nonatomic) NSDictionary *location;
@property (strong, nonatomic) CLLocationManager *locationManager;
@end
&lt;/pre&gt;&lt;p&gt;In the class&amp;#8217;s designated initializer, &lt;code&gt;initWithNibName:bundle:&lt;/code&gt;, we initialize and configure the location manager. We assign the view controller as the location manager&amp;#8217;s delegate and set the location manager&amp;#8217;s &lt;code&gt;accuracy&lt;/code&gt; property to &lt;code&gt;kCLLocationAccuracyKilometer&lt;/code&gt;. There is no need for better accuracy as we only need the location for weather data.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialize Location Manager
        self.locationManager = [[CLLocationManager alloc] init];
        // Configure Location Manager
        [self.locationManager setDelegate:self];
        [self.locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer];
    }
    return self;
}
&lt;/pre&gt;&lt;p&gt;The next piece of the puzzle is implementing, &lt;code&gt;locationManager:didUpdateLocations:&lt;/code&gt;, one of the methods of the &lt;code&gt;CLLocationManagerDelegate&lt;/code&gt; protocol, which is invoked each time the location manager has updated the device&amp;#8217;s location. The second argument of &lt;code&gt;locationManager:didUpdateLocations:&lt;/code&gt; is an array &lt;code&gt;CLLocation&lt;/code&gt; instances. The implementation of &lt;code&gt;locationManager:didUpdateLocations:&lt;/code&gt; also reveals the purpose of &lt;code&gt;_locationFound&lt;/code&gt;. Despite the fact that we tell the location manager to stop updating the location as soon as &lt;code&gt;locationManager:didUpdateLocations:&lt;/code&gt; is invoked, it is not uncommon that another update of the location invokes &lt;code&gt;locationManager:didUpdateLocations:&lt;/code&gt; again even after sending the location manager a message of &lt;code&gt;stopUpdatingLocation&lt;/code&gt;. If this were to happen, the same location would be added twice to the list of locations. The simple solution is to use a helper variable, &lt;code&gt;_locationFound&lt;/code&gt;, that keeps track of the state that we&amp;#8217;re in.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    if (![locations count] || _locationFound) return;
    // Stop Updating Location
    _locationFound = YES;
    [manager stopUpdatingLocation];
    // Current Location
    CLLocation *currentLocation = [locations objectAtIndex:0];
    // Reverse Geocode
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        if ([placemarks count]) {
            _locationFound = NO;
            [self processPlacemark:[placemarks objectAtIndex:0]];
        }
    }];
}
&lt;/pre&gt;&lt;p&gt;We extract the first location from the array of locations and use the &lt;code&gt;CLGeocoder&lt;/code&gt; class to reverse geocode that location. Reverse geocoding simply means finding out the name of the (closest) city and the location&amp;#8217;s country. The completion handler of &lt;code&gt;reverseGeocodeLocation:&lt;/code&gt; returns an array of placemarks. A placemark object is nothing more than a container for storing location data for a coordinate.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)processPlacemark:(CLPlacemark *)placemark {
    // Extract Data
    NSString *city = [placemark locality];
    NSString *country = [placemark country];
    CLLocationDegrees lat = placemark.location.coordinate.latitude;
    CLLocationDegrees lon = placemark.location.coordinate.longitude;
    // Create Location Dictionary
    NSDictionary *currentLocation = @{ MTLocationKeyCity : city,
                                       MTLocationKeyCountry : country,
                                       MTLocationKeyLatitude : @(lat),
                                       MTLocationKeyLongitude : @(lon) };
    // Add to Locations
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    NSMutableArray *locations = [NSMutableArray arrayWithArray:[ud objectForKey:MTRainUserDefaultsLocations]];
    [locations addObject:currentLocation];
    [locations sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:MTLocationKeyCity ascending:YES]]];
    [ud setObject:locations forKey:MTRainUserDefaultsLocations];
    // Synchronize
    [ud synchronize];
    // Update Current Location
    self.location = currentLocation;
    // Post Notifications
    NSNotification *notification2 = [NSNotification notificationWithName:MTRainDidAddLocationNotification object:self userInfo:currentLocation];
    [[NSNotificationCenter defaultCenter] postNotification:notification2];
}
&lt;/pre&gt;&lt;p&gt;In &lt;code&gt;processPlacemark:&lt;/code&gt;, we extract the data that we&amp;#8217;re looking for, city, country, latitude, and longitude, store it in a dictionary, and update the array of locations in the application&amp;#8217;s user defaults database. Note that we sort the array of locations before updating the user defaults database. The view controller&amp;#8217;s &lt;code&gt;location&lt;/code&gt; property is updated with the new location and a notification is sent to notify any object interested in this event.&lt;/p&gt;&lt;p&gt;That&amp;#8217;s not all, though. I have also overridden the setter of the view controller&amp;#8217;s &lt;code&gt;location&lt;/code&gt; property. Because the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class is in charge of adding new locations, we can delegate a few additional responsibilities to this class, such as updating the default location in the user defaults database. Because other parts of the application also need to know about a change in location, a notification with name &lt;code&gt;MTRainLocationDidChangeNotification&lt;/code&gt; is posted. We also invoke &lt;code&gt;updateView&lt;/code&gt;, another helper method that we will implement shortly.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)setLocation:(NSDictionary *)location {
    if (_location != location) {
        _location = location;
        // Update User Defaults
        NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
        [ud setObject:location forKey:MTRainUserDefaultsLocation];
        [ud synchronize];
        // Post Notification
        NSNotification *notification1 = [NSNotification notificationWithName:MTRainLocationDidChangeNotification object:self userInfo:location];
        [[NSNotificationCenter defaultCenter] postNotification:notification1];
        // Update View
        [self updateView];
    }
}
&lt;/pre&gt;&lt;h3&gt;Step 7: Adding a Label&lt;/h3&gt;&lt;p&gt;We won&amp;#8217;t spend much time on the user interface in this tutorial, but to make sure that everything works as we expect, it is good to have some visual feedback by adding a label to the weather view controller&amp;#8217;s view displaying the selected location. Open &lt;strong&gt;MTWeatherViewController.h&lt;/strong&gt; and create an outlet of type &lt;code&gt;UILabel&lt;/code&gt; and name it &lt;code&gt;labelLocation&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
#import &amp;quot;MTLocationsViewController.h&amp;quot;
@interface MTWeatherViewController : UIViewController &amp;lt;MTLocationsViewControllerDelegate&amp;gt;
@property (weak, nonatomic) IBOutlet UILabel *labelLocation;
@end
&lt;/pre&gt;&lt;p&gt;Open &lt;strong&gt;MTWeatherViewController.xib&lt;/strong&gt;, add a label to the view controller&amp;#8217;s view, and connect the outlet with the newly added label (figure 6). In &lt;code&gt;updateView&lt;/code&gt; (&lt;strong&gt;MTWeatherViewController.m)&lt;/strong&gt;, we update the label with the new location as shown below.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130510-6.png" alt="Creating a Weather App for iOS with Forecast.io: Part 1 - Adding the Location Label to the Weather View Controller " /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 6: Adding the Location Label to the Weather View Controller&lt;/figcaption&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)updateView {
    // Update Location Label
    [self.labelLocation setText:[self.location objectForKey:MTLocationKeyCity]];
}
&lt;/pre&gt;&lt;h3&gt;Step 8: Implementing the Delegate Protocol&lt;/h3&gt;&lt;p&gt;Thanks to the work we have done so far, implementing the two methods of the &lt;code&gt;MTLocationsViewControllerDelegate&lt;/code&gt; protocol is easy. In &lt;code&gt;controllerShouldAddCurrentLocation:&lt;/code&gt;, we tell the location manager to start updating the location. In &lt;code&gt;controller:didSelectLocation:&lt;/code&gt;, we set the view controller&amp;#8217;s &lt;code&gt;location&lt;/code&gt; property to the location that the user selected in the locations view controller, which in turn invokes the setter method we overrode a bit earlier.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller {
    // Start Updating Location
    [self.locationManager startUpdatingLocation];
}
- (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location {
    // Update Location
    self.location = location;
}
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Final Touches&lt;/h2&gt;&lt;p&gt;Before wrapping up the first installment of this series, we need to add a few final touches. When the user launches the application, for example, the &lt;code&gt;location&lt;/code&gt; property of the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class needs to be set to the location stored in the application&amp;#8217;s user defaults. In addition, when the user launches our application for the very first time, a default location is not yet set in the application&amp;#8217;s user defaults. This isn&amp;#8217;t a big problem, but to offer a good user experience it would be better to automatically fetch the user&amp;#8217;s current location when the application launches for the first time.&lt;/p&gt;&lt;p&gt;We can make both changes by amending the weather view controller&amp;#8217;s &lt;code&gt;viewDidLoad&lt;/code&gt; as shown below. The view controller&amp;#8217;s location property is set to the location stored in the user defaults database. If no location is found, that is, &lt;code&gt;self.location&lt;/code&gt; is &lt;code&gt;nil&lt;/code&gt;, we tell the location manager to start updating the location. In other words, when the application is launched for the first time, the current location is automatically retrieved and stored.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)viewDidLoad {
    [super viewDidLoad];
    // Load Location
    self.location = [[NSUserDefaults standardUserDefaults] objectForKey:MTRainUserDefaultsLocation];
    if (!self.location) {
        [self.locationManager startUpdatingLocation];
    }
}
&lt;/pre&gt;&lt;p&gt;There is one more loose end that we need to tie up. When a new location is added to the array of locations, the weather view controller posts a notification. We need to update the &lt;code&gt;MTLocationsViewController&lt;/code&gt; class so that it adds itself as an observer for these notifications. By doing so, the locations view controller can update its table view whenever a new location is added.&lt;/p&gt;&lt;p&gt;Revisit &lt;strong&gt;MTLocationsViewController.m&lt;/strong&gt; and update the &lt;code&gt;initWithNibName:bundle:&lt;/code&gt; as shown below. We add the view controller as an observer for notifications with a name of &lt;code&gt;MTRainDidAddLocationNotification&lt;/code&gt;. The implementation of &lt;code&gt;didAddLocation:&lt;/code&gt; is straightforward, that is, we add the new location to the array of locations, sort the array by city, and reload the table view.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Load Locations
        [self loadLocations];
        // Add Observer
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didAddLocation:) name:MTRainDidAddLocationNotification object:nil];
    }
    return self;
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)didAddLocation:(NSNotification *)notification {
    NSDictionary *location = [notification userInfo];
    [self.locations addObject:location];
    [self.locations sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:MTLocationKeyCity ascending:YES]]];
    [self.tableView reloadData];
}
&lt;/pre&gt;&lt;p&gt;Don&amp;#8217;t forget to remove the view controller as an observer in the view controller&amp;#8217;s &lt;code&gt;dealloc&lt;/code&gt; method. It is also good practice to set the view controller&amp;#8217;s &lt;code&gt;delegate&lt;/code&gt; property to &lt;code&gt;nil&lt;/code&gt; in &lt;code&gt;dealloc&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)dealloc {
    // Remove Observer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    if (_delegate) {
        _delegate = nil;
    }
}
&lt;/pre&gt;&lt;p&gt;Build and run the application to see how all this works together. You may want to run the application in the iOS Simulator instead of a on physical device, because the iOS Simulator supports location simulation (figure 7), which makes it much easier to test location based applications such as the one we created.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130510-7.png" alt="Creating a Weather App for iOS with Forecast.io: Part 1 - Simulating Locations with the iOS Simulator " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 7: Simulating Locations with the iOS Simulator&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Even though we haven&amp;#8217;t even touched the Forecast API, we did quite a bit of work in this article. I hope you have tried CocoaPods and are convinced of its power and flexibility. In the next installment of this series, we focus on the Forecast API and the AFNetworking library.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/WlKCi2IWoag" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-project-setup/feed/</wfw:commentRss> <slash:comments>4</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-project-setup/</feedburner:origLink></item> <item><title>iOS SDK: Customizing Popovers</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/h6IW_c1OyYM/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-customizing-popovers/#comments</comments> <pubDate>Thu, 09 May 2013 15:47:26 +0000</pubDate> <dc:creator>Aaron Crabtree</dc:creator> <category><![CDATA[iOS SDK]]></category> <category><![CDATA[custom popover]]></category> <category><![CDATA[ios]]></category> <category><![CDATA[UIPopoverBackgroundView]]></category> <category><![CDATA[UIPopoverController]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=16090</guid> <description>&lt;p&gt;Popovers are a great way to display supplementary information in an iPad app. Inevitably, as with most iOS objects, a little customization goes a long way in creating a design that is unique and fits in with your own app. In this tutorial, we will build a basic popover, then explore customizations one at a time, giving you an easy-to-follow path to implement customizations in your own app.&lt;br
/&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Setting Up Your Project&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;Launch Xcode and choose &lt;em&gt;File &amp;gt; New &amp;gt; Project&lt;/em&gt; to create a new project. Select an &lt;strong&gt;iOS Single View Application&lt;/strong&gt; and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-customizing-popovers/attachment/custom-popovers-create-new-project/" rel="attachment wp-att-16133"&gt;&lt;img
class="alignnone size-full wp-image-16133" alt="Figure 1" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/aaron-crabtree/custom-popovers-create-new-project.jpg" width="596" height="404" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 1&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;Fill in the text fields with your project name, organization name, and company identifier. Select &lt;strong&gt;iPad&lt;/strong&gt; from the &lt;em&gt;Devices&lt;/em&gt; drop down and make sure the box next to &lt;em&gt;Use Automatic Reference Counting&lt;/em&gt; is checked. Leave the boxes for &lt;em&gt;Use Storyboards&lt;/em&gt; and &lt;em&gt;Include Unit Tests&lt;/em&gt; unchecked and click &lt;strong&gt;Next&lt;/strong&gt;. Choose a location to save your file and click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-customizing-popovers/attachment/custom-popover-naming-project/" rel="attachment wp-att-16129"&gt;&lt;img
class="alignnone size-full wp-image-16129" alt="Figure 2" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/aaron-crabtree/custom-popover-naming-project.jpg" width="600" height="404" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 2&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Adding a Navigation Controller&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;Let’s use a navigation controller so that we can add a button to show the popover. Click on &lt;em&gt;AppDelegate.m&lt;/em&gt; and find the &lt;code&gt;application:didFinishLaunchingWithOptions:&lt;/code&gt; method. Add the following code to create a navigation controller and set it as the root view controller.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = navController;&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;Now we can add a plus button to the navigation bar. Click on &lt;em&gt;ViewController.m&lt;/em&gt; and add the following code to the &lt;code&gt;viewDidLoad&lt;/code&gt; method just below &lt;code&gt;[super viewDidLoad];&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;UIBarButtonItem *popoverButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
                     target:self
                     action:@selector(showPopover:)];
self.navigationItem.rightBarButtonItem = popoverButton;
&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;UIBarButtonSystemItemAdd&lt;/code&gt; creates a plus button; we’ll add it to the right side of the navigation bar. Next we’ll implement the &lt;code&gt;showPopover:&lt;/code&gt; method used as the selector.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Showing the Popover&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;Before implementing the &lt;code&gt;showPopover:&lt;/code&gt; method, let’s add a property for the popover controller. Click on the &lt;em&gt;ViewController.h&lt;/em&gt; file and add the following property.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;@property (nonatomic, strong) UIPopoverController *popController;&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;Navigate back to the &lt;em&gt;ViewController.m&lt;/em&gt; file and declare the &lt;code&gt;showPopover:&lt;/code&gt; method in the class extension as demonstrated below.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;@interface ViewController ()
- (void)showPopover:(id)sender;
@end&lt;/pre&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt;Add the following code to define the method under &lt;code&gt;@implementation&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;- (void)showPopover:(id)sender
{
    if (self.popController.popoverVisible) {
        [self.popController dismissPopoverAnimated:YES];
        return;
    }
    UIViewController *contentViewController = [[UIViewController alloc] init];
    contentViewController.view.backgroundColor = [UIColor yellowColor];
    UIPopoverController *popController = [[UIPopoverController alloc] initWithContentViewController:contentViewController];
    popController.popoverContentSize = CGSizeMake(300.0f, 600.0f);
    self.popController = popController;
    [self.popController presentPopoverFromBarButtonItem:sender
                    permittedArrowDirections:UIPopoverArrowDirectionUp
                                    animated:YES];
}&lt;/pre&gt;&lt;p&gt;First we check to see if the popover is already being shown on the screen. If it is visible, the popover is dismissed and the method returns. If the popover is not being shown on the screen, we create a view controller to be displayed in the popover. Then we create the popover controller and set its size. The last line of code tells the popover controller to present itself from the navigation bar button that was tapped &amp;#8211; in this case the plus button -and allows the arrow direction to point up only. One benefit to using this method is that if the user taps another button on the navigation bar, the tap is passed through to the navigation bar.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Testing the Standard Popover&lt;/h2&gt;&lt;p&gt;At this point, we have implemented a standard popover. Build and run your project and tap the plus button to see a basic popover appear. Let’s take a look at the basics of customizing its appearance.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;5.&lt;/span&gt; Subclassing &lt;code&gt;UIPopoverBackgroundView&lt;/code&gt;&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;In order to customize the appearance of the popover, we’ll need to subclass &lt;code&gt;UIPopoverBackgroundView&lt;/code&gt;. Click &lt;em&gt;File &amp;gt; New &amp;gt; File&lt;/em&gt;, choose an &lt;strong&gt;iOS Cocoa Touch Objective-C Class&lt;/strong&gt;, and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-customizing-popovers/attachment/custom-popover-create-new-file/" rel="attachment wp-att-16128"&gt;&lt;img
class="alignnone size-full wp-image-16128" alt="Figure 3" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/aaron-crabtree/custom-popover-create-new-file.jpg" width="600" height="405" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 3&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;Name the class &lt;em&gt;PopoverBackgroundView&lt;/em&gt; and choose &lt;code&gt;UIPopoverBackgroundView&lt;/code&gt; from the &lt;em&gt;Subclass of&lt;/em&gt; drop down.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt;&lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-customizing-popovers/attachment/custom-popover-naming-subclass/" rel="attachment wp-att-16130"&gt;&lt;img
class="alignnone size-full wp-image-16130" alt="Figure 4" src="http://cdn.tutsplus.com/mobile.tutsplus.com/authors/aaron-crabtree/custom-popover-naming-subclass.jpg" width="600" height="405" /&gt;&lt;/a&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 4&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt;There are two &lt;code&gt;UIPopoverBackgroundView&lt;/code&gt; properties that need to be overridden. Add the following code to synthesize the arrow direction and arrow offset, overriding the setter and getter methods for these two properties.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
@synthesize arrowDirection  = _arrowDirection;
@synthesize arrowOffset     = _arrowOffset;&lt;/pre&gt;&lt;h3&gt;Step 4&lt;/h3&gt;&lt;p&gt;There are three class methods that need to be overridden. Let’s define some values to use with the methods.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;#define kArrowBase 30.0f
#define kArrowHeight 20.0f
#define kBorderInset 8.0f&lt;/pre&gt;&lt;h3&gt;Step 5&lt;/h3&gt;&lt;p&gt;Add the code below to override the &lt;code&gt;arrowBase&lt;/code&gt;, &lt;code&gt;arrowHeight&lt;/code&gt; and &lt;code&gt;contentViewInsets&lt;/code&gt; methods.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;+ (CGFloat)arrowBase
{
    return kArrowBase;
}
+ (CGFloat)arrowHeight
{
    return kArrowHeight;
}
+ (UIEdgeInsets)contentViewInsets
{
    return UIEdgeInsetsMake(kBorderInset, kBorderInset, kBorderInset, 		kBorderInset);
}&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;arrowBase&lt;/code&gt; method determines the width of the arrow’s base, while the &lt;code&gt;arrowHeight&lt;/code&gt; method determines the height of the arrow. The &lt;code&gt;contentViewInsets&lt;/code&gt; method indicates how far from the edge of the background to display the content.&lt;/p&gt;&lt;h3&gt;Step 6&lt;/h3&gt;&lt;p&gt;Let’s add a background color so we can see the different pieces clearly. Add the following code inside the &lt;code&gt;if&lt;/code&gt; statement in the &lt;code&gt;initWithFrame:&lt;/code&gt; method.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;self.backgroundColor = [UIColor grayColor];&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;6.&lt;/span&gt; Setting the Popover Background View Class Property&lt;/h2&gt;&lt;p&gt;Before we can test the popover, we’ll need to import and set the popover controller’s popover background view class property. Click on the &lt;em&gt;ViewController.m&lt;/em&gt; file and import the popover background view header file as demonstrated below.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;#import &amp;quot;PopoverBackgroundView.h&amp;quot;&lt;/pre&gt;&lt;p&gt;While we&amp;#8217;re still in the &lt;em&gt;ViewController.m&lt;/em&gt; file, add the following line of code just below where we created the &lt;code&gt;UIPopoverController&lt;/code&gt; in the &lt;code&gt;showPopover:&lt;/code&gt; method.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;popController.popoverBackgroundViewClass = [PopoverBackgroundView class];&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;7.&lt;/span&gt; Testing the Popover Background View&lt;/h2&gt;&lt;p&gt;Build and run the project and tap the plus button to see the popover. You can see that the standard popover has been replaced with the customizations we’ve added so far. The gray border around the popover shows the insets returned from the &lt;code&gt;contentViewInsets&lt;/code&gt; method. You can adjust the insets as needed to achieve a desired look. We’ll draw an arrow later in the tutorial to display on the screen.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;8.&lt;/span&gt; Setting the Shadows and Rounded Corners&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;wantsDefaultContentAppearance&lt;/code&gt; method determines whether the default inset shadows and rounded corners are displayed in the popover. By returning &lt;code&gt;NO&lt;/code&gt;, the popover background view will no longer show the default shadows and rounded corners, allowing you to implement your own. Add the following code to override the method.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;+ (BOOL)wantsDefaultContentAppearance
{
    return NO;
}&lt;/pre&gt;&lt;p&gt;Build and run the project and you will be able to see the difference.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;9.&lt;/span&gt; Adding the Arrow&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt;We’ll need to create and manage the arrow ourselves; let’s declare a property for an image view that will display the arrow. Add the following code to the class extension.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;@property (nonatomic, strong) UIImageView *arrowImageView; &lt;/pre&gt;&lt;p&gt;Now we can instantiate the image view. Replace the code inside the &lt;code&gt;if&lt;/code&gt; statement in &lt;code&gt;initWithFrame:&lt;/code&gt; with the following code.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;self.backgroundColor = [UIColor clearColor];
UIImageView *arrowImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
self.arrowImageView = arrowImageView;
[self addSubview:self.arrowImageView];&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt;Let’s change the border inset by updating the the &lt;code&gt;kBorderInset&lt;/code&gt; defined in PopoverBackgroundView.m with the following code.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;#define kBorderInset 0.0f&lt;/pre&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt;In order to draw the arrow, we’ll need to declare a method to perform the drawing. Add the following method declaration in the class extension in &lt;em&gt;PopoverBackgroundView.m&lt;/em&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;- (UIImage *)drawArrowImage:(CGSize)size;&lt;/pre&gt;&lt;h3&gt;Step 4&lt;/h3&gt;&lt;p&gt;Now add the method definition under &lt;code&gt;@implementation&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;- (UIImage *)drawArrowImage:(CGSize)size
{
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [[UIColor clearColor] setFill];
    CGContextFillRect(ctx, CGRectMake(0.0f, 0.0f, size.width, size.height));
    CGMutablePathRef arrowPath = CGPathCreateMutable();
    CGPathMoveToPoint(arrowPath, NULL, (size.width/2.0f), 0.0f);
    CGPathAddLineToPoint(arrowPath, NULL, size.width, size.height);
    CGPathAddLineToPoint(arrowPath, NULL, 0.0f, size.height);
    CGPathCloseSubpath(arrowPath);
    CGContextAddPath(ctx, arrowPath);
    CGPathRelease(arrowPath);
    UIColor *fillColor = [UIColor yellowColor];
    CGContextSetFillColorWithColor(ctx, fillColor.CGColor);
    CGContextDrawPath(ctx, kCGPathFill);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}&lt;/pre&gt;&lt;p&gt;Instead of using an imported image, the code above programmatically creates the arrow.&lt;/p&gt;&lt;h3&gt;Step 5&lt;/h3&gt;&lt;p&gt;Each time the bounds of the popover background view subclass changes, the frame of the arrow needs to be recalculated. We can accomplish this by overriding &lt;code&gt;layoutSubviews&lt;/code&gt;. Add the following code to &lt;em&gt;PopoverBackgroundView.m&lt;/em&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;- (void)layoutSubviews
{
    [super layoutSubviews];
	CGSize arrowSize = CGSizeMake([[self class] arrowBase], [[self class] arrowHeight]);
    self.arrowImageView.image = [self drawArrowImage:arrowSize];
    self.arrowImageView.frame = CGRectMake(((self.bounds.size.width - arrowSize.width) kBorderInset), 0.0f, arrowSize.width, arrowSize.height);
}&lt;/pre&gt;&lt;p&gt;The frame of the arrow’s image view and the arrow’s image are calculated based on the bounds of the popover background view, the border’s insets, and the arrow&amp;#8217;s base and height.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;10.&lt;/span&gt; Testing the Popover&lt;/h2&gt;&lt;p&gt;Build and run your project to see the customized popover. Even though the border inset is set to zero, the arrow is adjusted to line up with the inside edge of the right inset. By subtracting the border inset when determining the x coordinate for the image view frame for the arrow, we are able to align the image view appropriately.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;This tutorial is designed to get you up and running with customizing a popover. There are many directions you can take the project from here; for example, adding another image view to display a custom border image. To do this, you would follow a similar pattern like we did when we created the image view for the arrow. Furthermore, you may want to customize the popover based on the arrow’s direction. In layoutSubviews, a series of if statements could help you test for the arrow’s direction so you could adjust the arrow accordingly. Leave a comment or question below if you have a specific direction you’d like to go with your customizations.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/h6IW_c1OyYM" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-customizing-popovers/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-customizing-popovers/</feedburner:origLink></item> <item><title>Build an AudioPlayer with PhoneGap: Application Tuning</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/SvPPSVbeEqA/</link> <comments>http://mobile.tutsplus.com/tutorials/phonegap/build-an-audioplayer-with-phonegap-application-tuning/#comments</comments> <pubDate>Wed, 08 May 2013 15:44:00 +0000</pubDate> <dc:creator>Aurelio De Rosa</dc:creator> <category><![CDATA[PhoneGap]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=16364</guid> <description>&lt;p&gt;This is the third and final part of the series about &lt;em&gt;Audero Audio Player&lt;/em&gt;. In this article, I will go over the remaining files so that you can finish the project and play around with it.&lt;br
/&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Series Overview&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=16347"&gt;Application Setup&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=16358"&gt;Application Logic&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=16364"&gt;Application Tuning&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr
/&gt;&lt;h2&gt;Style Tuning&lt;/h2&gt;&lt;p&gt;jQuery Mobile does a lot of the work for you by enhancing pages&amp;#8217; elements for devices with smaller screens. However, there are some that I don&amp;#8217;t care for, and we&amp;#8217;ll adjust these in our &lt;code&gt;style.css&lt;/code&gt; file. This is also used to style the player&amp;#8217;s markup.&lt;/p&gt;&lt;p&gt;By default, even if you don&amp;#8217;t have buttons within the header or the footer of a page, the framework still reserves some space on both side of the elements and truncates long titles. This behavior is applied to other elements as well. We can change it simply by applying the rule &lt;code&gt;white-space: normal !important;&lt;/code&gt; to our targeted elements as &lt;code&gt;.ui-title&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The source of the stylesheet is shown here:&lt;/p&gt;&lt;pre class="brush: css; title: ;"&gt;
.ui-header .ui-title,
.ui-footer .ui-title,
.ui-btn-inner *
{
  white-space: normal !important;
}
.photo
{
  text-align: center;
}
#player-play,
#player-stop
{
  display: inline-block;
  width: 48px;
  height: 48px;
}
#player-play
{
  background-image: url('../images/play.png');
}
#player-stop
{
  background-image: url('../images/stop.png');
}
#time-slider
{
  display: none;
}
div.ui-slider-track
{
  margin: 0;
  width: 100%;
}
&lt;/pre&gt;&lt;h3&gt;jQuery Mobile Custom Configuration&lt;/h3&gt;&lt;p&gt;jQuery Mobile has a default configuration that should be good enough for most projects with simple requirements. However, there will be times when you will want to modify or take control of some default behavior. You can achieve this by writing a configuration file. The file &lt;code&gt;jquery.mobile.config.js&lt;/code&gt; is exactly where we&amp;#8217;ll have the configuration. Please note that you must include the configuration file &lt;strong&gt;before&lt;/strong&gt; the jQuery Mobile files. When jQuery Mobile starts, it fires the &lt;code&gt;mobileinit&lt;/code&gt; event, which is the one you must bind to override the default settings.&lt;/p&gt;&lt;p&gt;We&amp;#8217;ll make the change by assigning values to the properties of the &lt;code&gt;$.mobile&lt;/code&gt; object. I won&amp;#8217;t change a lot of properties. I&amp;#8217;ll instead change the option to have the text shown on the page loader widget, and the theme.&lt;/p&gt;&lt;p&gt;The full source of the file is listed below:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
$(document).on(
   'mobileinit',
   function()
   {
      // Page Loader Widget
      $.mobile.loader.prototype.options.text = 'Loading...';
      $.mobile.loader.prototype.options.textVisible = true;
      // Theme
      $.mobile.page.prototype.options.theme  = 'a';
      $.mobile.page.prototype.options.headerTheme = 'a';
      $.mobile.page.prototype.options.contentTheme = 'a';
      $.mobile.page.prototype.options.footerTheme = 'a';
      $.mobile.page.prototype.options.backBtnTheme = 'a';
   }
);
&lt;/pre&gt;&lt;h3&gt;Build Configuration&lt;/h3&gt;&lt;p&gt;The &lt;a
href="http://build.phonegap.com"&gt;Adobe PhoneGap Build&lt;/a&gt; service gives you the ability to specify the metadata of an application, like author and description, by using a configuration file. This file is called &lt;code&gt;config.xml&lt;/code&gt;. Explaining the format in depth is outside the scope of this series, but I&amp;#8217;ll give you a brief overview. If you want to read more on this topic, take a look at the &lt;a
href="https://build.phonegap.com/docs/config-xml"&gt;official documentation page&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;config.xml&lt;/code&gt; file follows the &lt;a
href="http://www.w3.org/TR/widgets/"&gt;W3C widget specification&lt;/a&gt; and must stay inside the app&amp;#8217;s root, at the same level of the &lt;code&gt;index.html&lt;/code&gt; file. Its first line is the XML declaration, and the root of the document is a &lt;code&gt;&amp;lt;widget&amp;gt;&lt;/code&gt; tag that has several possible attributes. The most important ones are &lt;code&gt;id&lt;/code&gt; (the unique identifier for your project), and &lt;code&gt;version&lt;/code&gt; (which specifies the version of the application). Inside the &lt;code&gt;&amp;lt;widget&amp;gt;&lt;/code&gt; tag, you can write the metadata of your application. In our file we&amp;#8217;ll use a lot of them, but the most important are the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;name&lt;/strong&gt; (required): The name of the application. It doesn&amp;#8217;t have to be unique.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;description&lt;/strong&gt; (required): The description of the application. It&amp;#8217;s particularly important because it will be shown in the app&amp;#8217;s marketplace listing.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;icon&lt;/strong&gt; (optional): The icon to display on the devices that will install your app. If you do not specify it, the Cordova logo will be used.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;splash&lt;/strong&gt; (optional): This tag sets the splash screen of the application, which is the image shown during loading.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;feature&lt;/strong&gt; (optional): Specifies the features you want to use. For example, Android, before installing any app, shows the user the permissions it requires and, if the user agrees, it goes on.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;preference&lt;/strong&gt; (optional): A set of preferences you want to apply to your app. It&amp;#8217;s a closed tag and you can have zero or more &lt;code&gt;&amp;lt;preference&amp;gt;&lt;/code&gt; tags inside the file. It has two attributes, and both are required: &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt;. There are a lot of preferences that you can define, but the most important one in my opinion is specifying the Cordova version used.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;access&amp;gt;&lt;/code&gt; tag is also very important because, to cite &lt;a
href="https://build.phonegap.com/docs/config-xml"&gt;the documentation&lt;/a&gt;, it &lt;q
cite="https://build.phonegap.com/docs/config-xml"&gt;provides your app with access to resources on other domains &amp;#8211; in particular, it allows your app to load pages from external domains that can take over your entire webview.&lt;/q&gt; Recalling what we discussed in the section &lt;strong&gt;Managing External Links&lt;/strong&gt; from the previous post, to open the external links in the Cordova WebView, we must add them to the app whitelist. Since our application won&amp;#8217;t retrieve links from external and unsafe sources, we can shorten the process to allow for any external resource using the &lt;code&gt;*&lt;/code&gt; special character. For example:&lt;/p&gt;&lt;p&gt;&lt;code&gt;&amp;lt;access origin="*" /&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;I&amp;#8217;ve pointed out the key points of the format, and now you can understand the source of the configuration file. The complete file is below:&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;widget xmlns     = &amp;quot;http://www.w3.org/ns/widgets&amp;quot;
        xmlns:gap = &amp;quot;http://phonegap.com/ns/1.0&amp;quot;
        id        = &amp;quot;com.audero.free.player.auderoaudioplayer&amp;quot;
        version   = &amp;quot;1.0.0&amp;quot;&amp;gt;
   &amp;lt;name&amp;gt;Audero Audio Player&amp;lt;/name&amp;gt;
   &amp;lt;description&amp;gt;Audero Audio Player is a basic audio player that collects the audio files and then allows the user to listen to them. This app also enables you to update the list at any time to include other files that may have been downloaded after running the operation for the first time. You can also remove any unwanted audio from the list by clicking an icon on the right side of the song's name. The sound list is ordered alphabetically with letter dividers to organize and group the list items, and has a search box to filter the files.&amp;lt;/description&amp;gt;
   &amp;lt;author href=&amp;quot;http://www.audero.it&amp;quot; email=&amp;quot;aurelioderosa@gmail.com&amp;quot;&amp;gt;Aurelio De Rosa&amp;lt;/author&amp;gt;
   &amp;lt;feature name=&amp;quot;http://api.phonegap.com/1.0/network&amp;quot;/&amp;gt;
   &amp;lt;feature name=&amp;quot;http://api.phonegap.com/1.0/media&amp;quot;/&amp;gt;
   &amp;lt;feature name=&amp;quot;http://api.phonegap.com/1.0/file&amp;quot;/&amp;gt;
   &amp;lt;feature name=&amp;quot;http://api.phonegap.com/1.0/notification&amp;quot;/&amp;gt;
   &amp;lt;preference name=&amp;quot;phonegap-version&amp;quot; value=&amp;quot;2.3.0&amp;quot; /&amp;gt;
   &amp;lt;preference name=&amp;quot;target-device&amp;quot; value=&amp;quot;universal&amp;quot; /&amp;gt;
   &amp;lt;access origin=&amp;quot;*&amp;quot; /&amp;gt;
   &amp;lt;!-- Icons --&amp;gt;
   &amp;lt;icon src=&amp;quot;icon.png&amp;quot; width=&amp;quot;64&amp;quot; height=&amp;quot;64&amp;quot; gap:role=&amp;quot;default&amp;quot; /&amp;gt;
   &amp;lt;icon src=&amp;quot;images/icon-72x72.png&amp;quot; width=&amp;quot;72&amp;quot; height=&amp;quot;72&amp;quot; gap:platform=&amp;quot;android&amp;quot; gap:density=&amp;quot;hdpi&amp;quot; /&amp;gt;
   &amp;lt;icon src=&amp;quot;images/icon-96x96.png&amp;quot; width=&amp;quot;96&amp;quot; height=&amp;quot;96&amp;quot; gap:platform=&amp;quot;android&amp;quot; gap:density=&amp;quot;xhdpi&amp;quot; /&amp;gt;
   &amp;lt;icon src=&amp;quot;images/icon-72x72.png&amp;quot; width=&amp;quot;72&amp;quot; height=&amp;quot;72&amp;quot; gap:platform=&amp;quot;ios&amp;quot; /&amp;gt;
   &amp;lt;!-- Splash Screens --&amp;gt;
   &amp;lt;gap:splash src=&amp;quot;splash.png&amp;quot; /&amp;gt;
   &amp;lt;gap:splash src=&amp;quot;images/splash-160x220.png&amp;quot; gap:platform=&amp;quot;android&amp;quot; gap:density=&amp;quot;ldpi&amp;quot; /&amp;gt;
   &amp;lt;gap:splash src=&amp;quot;splash.png&amp;quot; gap:platform=&amp;quot;android&amp;quot; gap:density=&amp;quot;mdpi&amp;quot; /&amp;gt;
   &amp;lt;gap:splash src=&amp;quot;images/splash-450x650.png&amp;quot; gap:platform=&amp;quot;android&amp;quot; gap:density=&amp;quot;hdpi&amp;quot; /&amp;gt;
&amp;lt;/widget&amp;gt;
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;Running the Application&lt;/h2&gt;&lt;p&gt;In the last section, all the business logic, HTML and CSS files for the application were built, so now it&amp;#8217;s time to set the entry functions for the application and play. The targeted function will be the &lt;code&gt;initApplication()&lt;/code&gt; method of the &lt;code&gt;Application&lt;/code&gt; class. It will run once Cordova is fully loaded, ensuring that you can safely call the Cordova APIs. To do this,  we&amp;#8217;ll set &lt;code&gt;initApplication()&lt;/code&gt; as a callback function for the &lt;code&gt;deviceready&lt;/code&gt; event by adding the following code to the &lt;code&gt;index.html&lt;/code&gt; file. You can see this by looking at the next snippet:&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;script&amp;gt;
  $(document).on('pagebeforecreate orientationchange', Application.updateIcons);
  $(document).one('deviceready', Application.initApplication);
&amp;lt;/script&amp;gt;
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;Possible Improvements&lt;/h2&gt;&lt;p&gt;You are now at the end of the project. That being said, every project has room for improvements and new feature, so before I conclude the series, I would like to suggest some of these to you.&lt;/p&gt;&lt;p&gt;The first feature that you can add is the internationalization (i18n) of the application. Our player doesn&amp;#8217;t have much text, so translating it into other languages should be very easy. To translate the application, you can use the &lt;a
href="http://docs.phonegap.com/en/2.3.0/cordova_globalization_globalization.md.html#Globalization" target="_blank"&gt;Globalization API&lt;/a&gt;, an API added to the core starting from version 2.2.0. In addition, a specific jQuery library like &lt;a
href="http://code.google.com/p/jquery-i18n-properties/"&gt;jquery-i18n-properties&lt;/a&gt; or &lt;a
href="http://recursive-design.com/projects/jquery-i18n/"&gt;jQuery-i18n&lt;/a&gt; would surely be useful for this feature.&lt;/p&gt;&lt;p&gt;Other minor suggestions are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Allow the user to create playlist.&lt;/li&gt;&lt;li&gt;Create a &amp;#8220;Play All&amp;#8221; button to play all the songs in the list.&lt;/li&gt;&lt;li&gt;Create a ratings system for the audio so that the user can filter and order songs by rating.&lt;/li&gt;&lt;li&gt;Add a &amp;#8220;Repeat&amp;#8221; button so that the user can continue listening to the current song.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These suggestions are just some of the potential improvements you can make to the &lt;em&gt;Audero Audio Player&lt;/em&gt;. Using the information from this tutorial and your own skills, you can do much, much more.&lt;/p&gt;&lt;hr
/&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;As you&amp;#8217;ve seen throughout this series, you can build powerful and useful apps using web technologies and popular frameworks. Now it&amp;#8217;s your turn to play around with this project. Try starting your own project to test what you learned in this series!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/SvPPSVbeEqA" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/phonegap/build-an-audioplayer-with-phonegap-application-tuning/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/phonegap/build-an-audioplayer-with-phonegap-application-tuning/</feedburner:origLink></item> <item><title>Tuts+ Premium Cash Back Offer: 3 Days to Go</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/eBXENG6WVdU/</link> <comments>http://mobile.tutsplus.com/articles/news/try-tuts-premium-get-cash-back/#comments</comments> <pubDate>Tue, 07 May 2013 16:30:36 +0000</pubDate> <dc:creator>Joel Bankhead</dc:creator> <category><![CDATA[News]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=16930</guid> <description>&lt;p&gt;&lt;strong&gt;This offer ends soon! Act now and don’t miss out on cash back when trying a monthly Tuts+ Premium subscription.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;At $19 a month, Tuts+ Premium is fantastic value. But it&amp;#8217;s even better when we hand your first $19 right back to you!&lt;/p&gt;&lt;p&gt;For a limited time we&amp;#8217;re offering $19 cash back to new Tuts+ Premium monthly subscribers when signing up via PayPal. If you’ve been thinking about checking out our extensive library of courses, tutorials, eBooks and guides there’s never been a better time to join up and dive in.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;This offer ends at noon on the 20th of May AEST, so act fast.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a
href="https://tutsplus.com/paypal-cash-back-offer/?utm_source=mobiletutsend&amp;#038;utm_medium=post&amp;#038;utm_campaign=paypal_cashback&amp;#038;wt.mc_id=paypal"&gt;Become a Tuts+ Premium Member and take your creative &amp;#038; technical skills to a new level.&lt;/a&gt;&lt;br
/&gt;&lt;/p&gt;&lt;hr
/&gt; What can you learn on Tuts+ Premium? Glad you asked! Currently, more than 15,000 members are sharpening their skills in a wide range of areas including web design, web development, Photoshop, vectors, video effects, and many more.&lt;/p&gt;&lt;p&gt;With Tuts+ Premium you learn from expert instructors in every field, such as:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Designer Justin Maller (Nike, Verizon, DC Shoe Co.)&lt;/li&gt;&lt;li&gt;Illustrator Russell Tate (McDonald&amp;#8217;s, Coca-Cola)&lt;/li&gt;&lt;li&gt;Developer Burak Guzel (Software Engineer at Facebook)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Join now and get instant access to your very own library of courses, tutorials, and eBooks, available whenever you need them. Become part of a community of over 15,000 members and start getting better at the skills you care about. Our dedicated team adds new content weekly, so there&amp;#8217;s always something fresh to sink your teeth into.&lt;/p&gt;&lt;p&gt;&lt;a
href="https://tutsplus.com/paypal-cash-back-offer/?utm_source=mobiletutsend&amp;#038;utm_medium=post&amp;#038;utm_campaign=paypal_cashback&amp;#038;wt.mc_id=paypal"&gt;Join Tuts+ Premium&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/eBXENG6WVdU" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/articles/news/try-tuts-premium-get-cash-back/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/articles/news/try-tuts-premium-get-cash-back/</feedburner:origLink></item> <item><title>How To Submit an iOS App to the App Store</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/Kn8UGqXgb3M/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/how-to-submit-an-ios-app-to-the-app-store/#comments</comments> <pubDate>Mon, 06 May 2013 17:09:11 +0000</pubDate> <dc:creator>Bart Jacobs</dc:creator> <category><![CDATA[iOS SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=16812</guid> <description>&lt;p&gt;You have worked weeks or months on your first iOS application and you are ready to submit your masterpiece to Apple&amp;#8217;s App Store. How do you do this? Is your application ready for submission? I am sure that some of these questions have entered your mind at one point or another. Is submitting an application as simple as sending Apple your application&amp;#8217;s binary? Not quite. With this tutorial, I will provide you with a detailed map to get your application submitted to Apple&amp;#8217;s App Store.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Introduction&lt;/h2&gt;&lt;p&gt;Even though the App Store review process is a black box for the most part, that doesn&amp;#8217;t mean that you can&amp;#8217;t prepare yourself and your application for Apple&amp;#8217;s review process. Apple provides guidelines to help you stay within the  sometimes invisible boundaries of what is and isn&amp;#8217;t allowed in the App Store.&lt;/p&gt;&lt;p&gt;The first time you submit an application to the App Store is exciting and nerve-racking at the same time. Even for experienced iOS developers, submitting an application to the App Store is often a stressful undertaking because it is something that most developers don&amp;#8217;t do on a daily basis.&lt;/p&gt;&lt;p&gt;Throughout this article, I am assuming that you are a registered iOS developer which means that you are enrolled in Apple&amp;#8217;s iOS Developer Program and are allowed to submit applications for publication in the App Store. To submit an iOS application to the App Store, you need to be a registered iOS developer. Red flag? Don&amp;#8217;t worry. You can enroll in Apple&amp;#8217;s iOS Developer Program by visiting &lt;a
href="https://developer.apple.com/programs/ios/"&gt;this link&lt;/a&gt; and clicking the &lt;strong&gt;Enroll Now&lt;/strong&gt; button.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-1.png" alt="How To Submit an iOS App to the App Store - Enrolling in Apple's iOS Developer Program" /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 1: Enrolling in Apple&amp;#8217;s iOS Developer Program&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Is your application ready?&lt;/h2&gt;&lt;h3&gt;Step 1: Testing&lt;/h3&gt;&lt;p&gt;An application isn&amp;#8217;t necessarily ready when you&amp;#8217;ve written the last line of code or implemented the final feature of the application&amp;#8217;s specification. Have you tested your application on one or more physical devices? Have you profiled your application for memory leaks and performance issues? Does your application crash from time to time? The family of iOS devices has grown substantially over the past years and it is important to test your application on as many iOS devices as you can lay your hands on. Common issues include not optimizing an application for the iPhone 5&amp;#8242;s 4&amp;#8243; screen or the iPad Mini&amp;#8217;s 7.9&amp;#8243; screen.&lt;/p&gt;&lt;p&gt;The iOS Simulator is a great tool, but it runs on your Mac, which has more memory and processing power than the phone in your pocket. I can assure you that the differences in performance between an old(er) iPhone 3GS and an iPhone 5 are like night and day. As an iOS developer, you should never get rid of an old iOS device as long as you build or maintain applications that can run on any of these older devices.&lt;/p&gt;&lt;p&gt;Apple&amp;#8217;s Review Process isn&amp;#8217;t airtight, but it is very capable of identifying problems that might affect your application&amp;#8217;s user experience. If your application crashes from time to time or it becomes slow after ten minutes of use, then you have some work to do before submitting it to the App Store. Even if Apple&amp;#8217;s review team doesn&amp;#8217;t spot the problem, your users will. If the people using your application are not pleased, they will leave bad reviews on the App Store, which may harm sales or inhibit downloads.&lt;/p&gt;&lt;h3&gt;Step 2: Rules and Guidelines&lt;/h3&gt;&lt;p&gt;As I mentioned earlier, Apple provides developers with a number of documents that are a great help during the creation and development process of your application. The documents that you should be aware of are the &lt;a
href="https://developer.apple.com/library/ios/#documentation/userexperience/conceptual/mobilehig/Introduction/Introduction.html"&gt;iOS Human Interface Guidelines&lt;/a&gt; and the &lt;a
href="https://developer.apple.com/appstore/resources/approval/guidelines.html"&gt;App Store Review Guidelines&lt;/a&gt;. Despite the availability of these documents, it seems that few developers take the time to browse them, let alone read them. It shouldn&amp;#8217;t be a surprise that some applications are therefore rejected even though the reason for the rejection is clearly stated in these documents.&lt;/p&gt;&lt;p&gt;Even if you don&amp;#8217;t intend to read the iOS Human Interface Guidelines or the App Store Review Guidelines, it is important to know about some of the rules that they talk about. Take a look at the short list below to get an idea of what your application should and shouldn&amp;#8217;t do.&lt;/p&gt;&lt;p&gt;Your application &amp;#8230;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;doesn&amp;#8217;t crash.&lt;/li&gt;&lt;li&gt;shouldn&amp;#8217;t use private API&amp;#8217;s.&lt;/li&gt;&lt;li&gt;shouldn&amp;#8217;t replicate the functionality of native applications.&lt;/li&gt;&lt;li&gt;should use In App Purchase for in-app (financial) transactions.&lt;/li&gt;&lt;li&gt;shouldn&amp;#8217;t use the camera or microphone without the user&amp;#8217;s knowledge.&lt;/li&gt;&lt;li&gt;only uses artwork that you have the copyright of or you have permission to use.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Keep in mind that this is a tiny subset of the guidelines included in the aforementioned documents. The majority of the rules and guidelines are trivial, but some are not and you might even violate some of them inadvertently. Let me give you an example. Before Apple started using its own maps, the MapKit framework used Google&amp;#8217;s maps. This was clear to the user because of the small Google logo in the bottom left corner of each map. However, if some part of your application&amp;#8217;s user interface covered or obscured Google&amp;#8217;s logo, your application would get rejected. This rule seems trivial, but it is a rule that is easily violated if you&amp;#8217;re not careful. Even automated tests won&amp;#8217;t cover you in this case.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Prerequisites&lt;/h2&gt;&lt;p&gt;Before you can even start thinking about submitting your application to the App Store, you need to make sure that you have an App ID, a valid distribution certificate, and a valid provisioning profile. Let me show you what this entails.&lt;/p&gt;&lt;h3&gt;Step 1: App ID&lt;/h3&gt;&lt;p&gt;Every application needs an App ID or application identifier. There are two types of application identifiers, (1) an &lt;strong&gt;explicit App ID&lt;/strong&gt; and (2) a &lt;strong&gt;wildcard App ID&lt;/strong&gt;. A wildcard App ID can be used for building and installing multiple applications. Despite the convenience of a wildcard App ID, an explicit App ID is &lt;strong&gt;required&lt;/strong&gt; if your application uses iCloud or makes use of other iOS features, such as Game Center, Apple Push Notifications, or In App Purchase.&lt;/p&gt;&lt;p&gt;If you&amp;#8217;re not sure what App ID best fits your project, then I recommend reading &lt;a
href="http://developer.apple.com/library/ios/#qa/qa1713/_index.html"&gt;Technical Note QA1713&lt;/a&gt; for more information about this topic.&lt;/p&gt;&lt;h3&gt;Step 2: Distribution Certificate&lt;/h3&gt;&lt;p&gt;To submit an application to the App Store, you need to create an iOS provisioning profile for distribution. To create such a provisioning profile, you first need to create a distribution certificate. The process for creating a distribution certificate is very similar to creating a development certificate. If you have tested your application on a physical device, then you are probably already familiar with the creation of a development certificate.&lt;/p&gt;&lt;p&gt;If you need to refresh your memory, I suggest reading &lt;a
href="http://developer.apple.com/library/ios/#documentation/IDEs/Conceptual/AppDistributionGuide/CodeSigningYourApps/CodeSigningYourApps.html"&gt;Apple&amp;#8217;s detailed guide&lt;/a&gt; about signing certificates and provisioning profiles. The process is not difficult once you understand how the various pieces of the puzzle fit together.&lt;/p&gt;&lt;h3&gt;Step 3: Provisioning Profile&lt;/h3&gt;&lt;p&gt;Once you&amp;#8217;ve created an App ID and a distribution certificate, you can create an iOS provisioning profile for distributing your application through the App Store. Keep in mind that you cannot use the same provisioning profile that you use for ad hoc distribution. You need to create a separate provisioning profile for App Store distribution. If you use a wildcard App ID for your project, then you can use the same provisioning profile for multiple applications.&lt;/p&gt;&lt;h3&gt;Step 4: Build Settings&lt;/h3&gt;&lt;p&gt;With the App ID, distribution certificate, and provisioning profile in place, it is time to configure your target&amp;#8217;s build settings in Xcode. This means selecting the target from the list of targets in Xcode&amp;#8217;s &lt;strong&gt;Project Navigator&lt;/strong&gt;, opening the &lt;strong&gt;Build Settings&lt;/strong&gt; tab at the top, and updating the settings in the &lt;strong&gt;Code Signing&lt;/strong&gt; section to match the distribution provisioning profile you created earlier. Newly added provisioning profiles are sometimes not immediately visible in the &lt;strong&gt;Code Signing&lt;/strong&gt; section of the build settings. Quitting and relaunching Xcode remedies this issue.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-2.png" alt="How To Submit an iOS App to the App Store - Configuring the Target's Build Settings" /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 2: Configuring the Target&amp;#8217;s Build Settings&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;Even though the code signing process is fairly simple once you understand it, it is something that trips up a lot of developers. I don&amp;#8217;t know a single Cocoa developer who hasn&amp;#8217;t run into code signing issues at some point in their career. Once you&amp;#8217;ve taken this hurdle, the rest of the submission process is fairly easy.&lt;/p&gt;&lt;h3&gt;Step 5: Deployment Target&lt;/h3&gt;&lt;p&gt;It is useful to write a few words about your application&amp;#8217;s deployment target. Each target in an Xcode project, has a deployment target, which indicates the minimum version of the operating system that the application can run on. It is up to you to set the deployment target, but keep in mind that modifying the deployment target is not something you can do without consequences once your application is in the App Store. If you increase the deployment target for an update of your application, then users who already purchased your application but don&amp;#8217;t meet the new deployment target, cannot run the update. It gets really problematic when a user downloads an update through iTunes (not the device), replacing the previous version on their computer, and then discovers that the new update doesn&amp;#8217;t run on their device.&lt;/p&gt;&lt;p&gt;I have two very simple tips with regards to your application&amp;#8217;s deployment target. (1) Be very careful when you decide to increase the deployment target of an existing application. Mention this in the application&amp;#8217;s release notes of the updates that precede the change and again in the update that uses the new deployment target. If your warn your customers well in advance, you have done all you can to prevent potential problems. (2) For new applications, I almost always set the deployment target to the last major release, iOS 6 at the time of writing. Because of the incredible adoption rate of new iOS releases, there is no harm in doing this. Some people think that they miss out on a large chunk of the market, but that is not true. Take the release of iOS 6 as an example. One month after the release of iOS 6, &lt;a
href="http://gigaom.com/2012/10/22/1-month-later-ios-6-adoption-hits-61-percent-in-u-s-canada/"&gt;more than 60% of iOS devices had upgraded to the new version of iOS&lt;/a&gt;. Unfortunately, &lt;a
href="http://thenextweb.com/google/2012/11/02/android-4-1-jelly-bean-hits-2-7-adoption-ics-at-25-8-gingerbread-still-on-over-half-of-devices/"&gt;the same isn&amp;#8217;t true for Android&lt;/a&gt;.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Assets&lt;/h2&gt;&lt;h3&gt;Step 1: Icons&lt;/h3&gt;&lt;p&gt;You probably know that an application icon is a vital component of every iOS application, but you need to make sure that your application ships with the correct sizes of the artwork. Take a look at the list below for an overview.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;iTunes Artwork: 1024px x 1024px (required)&lt;/li&gt;&lt;li&gt;iPad/iPad Mini: 72px x 72px &lt;strong&gt;and&lt;/strong&gt; 114px x 114px (required)&lt;/li&gt;&lt;li&gt;iPhone/iPod Touch: 57px x 57px &lt;strong&gt;and&lt;/strong&gt; 114px x 114px (required)&lt;/li&gt;&lt;li&gt;Search Icon: 29px x 29px &lt;strong&gt;and&lt;/strong&gt; 58px x 58px (optional)&lt;/li&gt;&lt;li&gt;Settings Application: 50px x 50px &lt;strong&gt;and&lt;/strong&gt; 100px x 100px (optional)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;It goes without saying that you don&amp;#8217;t need to include an application icon for the iPad/iPad Mini device family if your application only targets the iPhone/iPod Touch device family, and vice versa.&lt;/p&gt;&lt;h3&gt;Step 2: Screenshots&lt;/h3&gt;&lt;p&gt;Each application can have up to five screenshots and you must provide at least one. If you are developing a universal application, then you need to provide separate screenshots for iPhone/iPod Touch and iPad/iPad Mini. In addition, you can optionally include separate screenshots for the 3.5&amp;#8243; and the 4&amp;#8243; screen sizes of the iPhone/iPod Touch. This is quite a bit of work and you want to make sure that the screenshots show your application from its best side. Shiny Development sells a Mac application, &lt;a
href="http://shinydevelopment.com/status-magic/"&gt;Status Magic&lt;/a&gt; that helps you get the status bar in your screenshots right. Status Magic will save you quite a bit of time.&lt;/p&gt;&lt;p&gt;It is important to spend some time thinking about the screenshots. Your application&amp;#8217;s screenshots are often the only thing that a customer can use to decide whether she purchases or downloads your application or not. What a lot of developers don&amp;#8217;t know is that the screenshots don&amp;#8217;t have to be actual screenshots. The hard rule is that the size of each screenshot needs to be that of the screen size of the target device. Many companies are creative with this rule. Take a look at the screenshots of &lt;a
href="https://itunes.apple.com/us/app/wheres-my-water/id449735650"&gt;Where&amp;#8217;s My Water?&lt;/a&gt;, for example. By using this strategy, screenshots can be much more attractive and compelling.&lt;/p&gt;&lt;h3&gt;Step 3: Metadata&lt;/h3&gt;&lt;p&gt;Before you submit your application, it is a good idea to have your application&amp;#8217;s metadata at hand. This includes (1) your application&amp;#8217;s name, (2) the version number, (3) the primary (and an optional secondary) category, (4) a concise description, (5) keywords, and (6) a support URL. If you are submitting an update, then you can also provide information for the &lt;strong&gt;What&amp;#8217;s new in this Version&lt;/strong&gt; section.&lt;/p&gt;&lt;p&gt;Does your application require users to sign in? Then you also need to provide Apple with a test or demo account to make sure that the review team can immediately sign in and use your application without first having to sign up for an account.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Submission Preparation&lt;/h2&gt;&lt;p&gt;The submission process has become much easier since the release of Xcode 4. You can now validate and submit an application using Xcode, for example. First, however, you need to create your application in iTunes Connect.&lt;/p&gt;&lt;p&gt;Visit &lt;a
href="https://itunesconnect.apple.com"&gt;iTunes Connect&lt;/a&gt;, sign in with your iOS developer account, and click &lt;strong&gt;Manage Your Apps&lt;/strong&gt; on the right. Click the &lt;strong&gt;Add New App&lt;/strong&gt; in the top left, select &lt;strong&gt;iOS App&lt;/strong&gt;, and fill out the form.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-3.png" alt="How To Submit an iOS App to the App Store - Visit iTunes Connect to Get Started" /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 3: Visit iTunes Connect to Get Started&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 1: Basic Information&lt;/h3&gt;&lt;p&gt;The &lt;strong&gt;App Name&lt;/strong&gt;, which needs to be unique, is the name of your application as it will appear in the App Store. This can be different than the name that is displayed below your application icon on the home screen, but it is recommended to choose the same name. The &lt;strong&gt;SKU Number&lt;/strong&gt; is a unique string that identifies your application. I usually use the application&amp;#8217;s bundle identifier. The last piece of information is the &lt;strong&gt;Bundle ID&lt;/strong&gt; of your application. This means selecting the (wildcard or explicit) App ID that you created earlier from the drop down menu.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-4.png" alt="How To Submit an iOS App to the App Store - Specifying Name, SKU Number, and Bundle ID" /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 4: Specifying Name, SKU Number, and Bundle ID&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 2: Price and Availability&lt;/h3&gt;&lt;p&gt;In the next step, you specify your application&amp;#8217;s price and availability. Apple works with price tiers so that you don&amp;#8217;t have to specify a price for each country that Apple operates in. You can also specify in which stores your application should &amp;#8211; or shouldn&amp;#8217;t &amp;#8211; be available. The information that you enter in this step can be modified once your application is live in the App Store. In other words, you can change the price and availability of an application without having to submit an update.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-5.png" alt="How To Submit an iOS App to the App Store - Specifying Price and Availability" /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 5: Specifying Price and Availability&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 3: Metadata&lt;/h3&gt;&lt;p&gt;We&amp;#8217;ve already covered the application&amp;#8217;s metadata. The only aspect that I haven&amp;#8217;t talked about yet is your application&amp;#8217;s rating. Based on your application&amp;#8217;s content and functionality, it is given a rating. This rating is not only useful for telling users about your application&amp;#8217;s content and features, the rating is also used by the operating system for the parental controls features.&lt;/p&gt;&lt;p&gt;It is strongly recommended that you don&amp;#8217;t try to outsmart the rating system. Apple is well aware of this and will reject your application if it doesn&amp;#8217;t agree with the rating that you have set.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-6.png" alt="How To Submit an iOS App to the App Store - Entering Your Application's Metadata and Assigning a Rating" /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 6: Entering Your Application&amp;#8217;s Metadata and Assigning a Rating&lt;/figcaption&gt; &lt;/figure&gt;&lt;h3&gt;Step 4: Ready to Upload Binary&lt;/h3&gt;&lt;p&gt;Once your application&amp;#8217;s metadata is submitted, you will be presented with a summary of your application. Under &lt;strong&gt;Versions&lt;/strong&gt;, you should see the version that you submitted a moment ago. Click the &lt;strong&gt;View Details&lt;/strong&gt; button and click the &lt;strong&gt;Ready to Upload Binary&lt;/strong&gt; button in the top right. You are then asked one or more questions regarding your application and, if all went well, you should see a message telling you that you are now ready to upload your application binary. The status of your application has changed to &lt;strong&gt;Waiting for Upload&lt;/strong&gt;.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-7.png" alt="How To Submit an iOS App to the App Store - Your Application's Summary " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 7: Your Application&amp;#8217;s Summary &lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;5. &lt;/span&gt; Uploading Binary&lt;/h2&gt;&lt;p&gt;To submit your application, you need to create an &lt;strong&gt;archive&lt;/strong&gt; of your application. You can only create an archive by building your application on a &lt;strong&gt;physical device&lt;/strong&gt;. If you select the iOS Simulator in the active scheme, you will notice that the &lt;strong&gt;Archive&lt;/strong&gt; option in Xcode&amp;#8217;s &lt;strong&gt;Product&lt;/strong&gt; menu is grayed out. Connect an iOS device to your Mac, select it in the active scheme, and select &lt;strong&gt;Archive&lt;/strong&gt; from Xcode&amp;#8217;s &lt;strong&gt;Product&lt;/strong&gt; menu.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-8.png" alt="How To Submit an iOS App to the App Store - Archiving Your Application using Xcode " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 8: Archiving Your Application using Xcode &lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;If all went well, you should now have an archive and Xcode&amp;#8217;s Organizer should automatically open and show you the archive you just created. Select the archive from the list and click the &lt;strong&gt;Distribute&amp;#8230;&lt;/strong&gt; button on the right. From the options you are presented with, select &lt;strong&gt;Submit to the iOS App Store&lt;/strong&gt;. After entering your iOS developer account credentials and selecting the &lt;strong&gt;Application&lt;/strong&gt; and &lt;strong&gt;Code Signing Identity&lt;/strong&gt;, the application binary is uploaded to Apple&amp;#8217;s servers. During this process, your application is also validated. If an error occurs during the validation, the submission process will fail. The validation process is very useful as it will tell you if there is something wrong with your application binary that would otherwise result in a rejection by the App Store review team.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-9.png" alt="How To Submit an iOS App to the App Store - Archiving Your Application using Xcode " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 9: Archiving Your Application using Xcode &lt;/figcaption&gt; &lt;/figure&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-10.png" alt="How To Submit an iOS App to the App Store - Submit Your Application to the iOS App Store " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 10: Submit Your Application to the iOS App Store &lt;/figcaption&gt; &lt;/figure&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-11.png" alt="How To Submit an iOS App to the App Store - Enter Your iOS Developer Account Credentials " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 11: Enter Your iOS Developer Account Credentials &lt;/figcaption&gt; &lt;/figure&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-12.png" alt="How To Submit an iOS App to the App Store - Select Application and Code Signing Identity " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 12: Select Application and Code Signing Identity&lt;/figcaption&gt; &lt;/figure&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130504-13.png" alt="How To Submit an iOS App to the App Store - An Error is Shown if Validation Fails " /&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 13: An Error is Shown if Validation Fails&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;6. &lt;/span&gt; Waiting&lt;/h2&gt;&lt;p&gt;If the submission process went without problems, your application&amp;#8217;s status will change to &lt;strong&gt;Waiting for Review&lt;/strong&gt;. It takes several days for Apple to review your application and the time it takes, tends to fluctuate over time. To get an idea of the average review times of iOS and Mac applications, I recommend visiting the website of &lt;a
href="http://reviewtimes.shinydevelopment.com"&gt;Shiny Development&lt;/a&gt; (Dave Verwer). This will give you a good indication of how long the review process will take.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;The submission process is quite lengthy for a new application, but submitting an update to the App Store is much less cumbersome. Keep in mind that the submission process is much more involving if your application is localized in various languages as your application&amp;#8217;s metadata needs to be localized as well. However, localizing your application is well worth the effort as it often results in higher sales and positive customer feedback.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/Kn8UGqXgb3M" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/how-to-submit-an-ios-app-to-the-app-store/feed/</wfw:commentRss> <slash:comments>4</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/how-to-submit-an-ios-app-to-the-app-store/</feedburner:origLink></item> </channel> </rss><!-- Dynamic Page Served (once) in 1.297 seconds -->
