Thursday, March 19, 2015

iOS 7: Using NSURLSession for Asynchronous Networking

In iOS 7, Apple introduced NSURLSession, which is a suite of classes that replaces NSURLConnection as the preferred method of networking. In this article, we cover the benefits of using NSURLSession, and when and how to use it.

What are the benefits of using NSURLSession?

There are a number of new advantages and benefits of using NSURLSession:

  • Uploads and Downloads can be done in the Background
    • When the NSURLSession is created, a configuration option can be selected to allow background networking. This helps to save battery life, supports multitasking and allows developers to use the same delegate model as in-process transfers.
  • Allows the pause and resume for network operations
    • When the NSURLSession API is utilized, any networking task can be paused, stopped and restarted. There is no NSOperation subclassing required.
  • Configurable container for storing network request configuration
    • Each NSURLSession provides a configurable container for storing network requests. For instance, for setting an HTTP header option, we will need to only do this once and each subsequent request will utilize the same configuration
  • Allows a private storage which is subclassable
    • Each NSURLSession is subclassable and one can configure a session to use private storage on a per session basis. This allows one to have private storage objects outside of the global state.
  • Improved authentication handling
    • When using NSURLConnection, if an authentication challenge was issued, the challenge would come back for an arbitrary request, so one would not know exactly what request was getting the challenge. However, with NSURLSession, the delegate handles the authentication.
  • Rich delegate model
    • NSURLConnection does have some asynchronous block based methods. However, a delegate cannot be used with them. 
  • Uploads and downloads allowed through the file system. 
    • This encourages a separation of the data (i.e. file contents) from the metadata (i.e. URL and settings)
NSURLSession

NSURLSession is designed as a replacement API for NSURLConnection. An NSURLSession is made using an NSURLSessionConfiguration with an optional delegate. After the session is established, the network requirements are satisfied by creating NSURLSessionTask.
According to Apple's URL Loading Programming Guide, you can use the NSURLSession API in two ways: with a system-provided delegate or with your own delegate. In general, you must use your own delegate if your app does any of the following:
  • Uses background sessions to download or upload content while your app is not running.
  • Performs custom authentication.
  • Performs custom SSL certificate verification.
  • Decides whether a transfer should be downloaded to disk or displayed based on the MIME type returned by the server or other similar criteria.
  • Uploads data from a body stream (as opposed to an NSData object).
  • Limits caching programmatically.
  • Limits HTTP redirects programmatically.
If your app does not need to do any of these things, your app can use the system-provided delegates.
Basic sequence of method calls that your app needs to make and completion handler calls that your app receives when using NSURLSession with the system-provided delegate :
  1. Create the NSURLSessionConfiguration
  2. Create a session specifying a configuration object and a nil delegate.
  3. Create task objects within a session that each represent a resource request. The task objects are subclasses of NSURLSessionTaskNSURLSessionDataTask, NSURLSessionUploadTask, or NSURLSessionDownloadTask, depending on the behavior you are trying to achieve.  These objects are analogous to NSURLConnection objects, but give you more control and a unified delegate model.
  4. We need to have our delegate implement the required methods from the NSURLSessionDownloadDelegate protocol.
  5. When a task completes, the NSURLSession object calls the task's completion handler.
  6. When your app no longer needs a session, invalidate it by calling either either invalidateAndCancel (to cancel outstanding tasks) or finishTasksAndInvalidate (to allow outstanding tasks to finish before invalidating the object).







Important: If you are using the NSURLSession class without providing delegates, your app must create tasks using a call that takes a completionHandler parameter, because otherwise it cannot obtain data from the class.
Note: NSURLSession does not report server errors through the error parameter. The only errors your app receives through the error parameter are client-side errors, such as being unable to resolve the hostname or connect to the host. The error codes are described in URL Loading System Error Codes. Server-side errors are reported through the HTTP status code in the NSHTTPURLResponse object. For more information, read the documentation for the NSHTTPURLResponse and NSURLResponse classes.


Step #1: Creating the NSURLSessionConfiguration
There are three ways to create an NSURLSessionConfiguration:
  • defaultSessionConfiguration 
    • creates a configuration object that uses the global cache, cookie and credential storage objects. This configuration provides a session to look very much like the NSURLConnection.
  • ephemeralSessionConfiguration
    • This configuration is for "private" sessions and has no persistent storage for cache, cookie or credential storage objects
  • backgroundSessionConfiguration
    • This configuration is used for making networking calls from remote push notifications or while the app is suspended.
Once the NSURLSessionConfiguration is created, then the setting of various properties on it can be done as follows:

NSURLSessionConfiguration *sessionConfig =
[NSURLSessionConfiguration defaultSessionConfiguration];
 
// restricts network operations to Wifi
sessionConfig.allowsCellularAccess = NO;
 
// sets all requests to only accept JSON responses
[sessionConfig setHTTPAdditionalHeaders:
          @{@"Accept": @"application/json"}];
 
// configures timeouts & restricts app to only have one network connection to a host
sessionConfig.timeoutIntervalForRequest = 30.0;
sessionConfig.timeoutIntervalForResource = 60.0;
sessionConfig.HTTPMaximumConnectionsPerHost = 1;
Step #2: Creating the Session
With NSURLSession, you can create the tasks using the block based convenience methods, set up a delegate or both. For instance, if you want to download an image, then you will need to create an NSURLSessionDownloadTask.
// set the image URL
NSString *imageUrl = @"http://someImage.png";
 
// create the default session configuration
NSURLSessionConfiguration *sessionConfig =
  [NSURLSessionConfiguration defaultSessionConfiguration];
 
// create a session using the current class as a delegate
NSURLSession *session =
  [NSURLSession sessionWithConfiguration:sessionConfig
                                delegate:self
                           delegateQueue:nil];

Step #3: Download the image by creating a task with a completion handler
// the task is created from a session
NSURLSessionDownloadTask *getImageTask =
[session downloadTaskWithURL:[NSURL URLWithString:imageUrl]
 
    completionHandler:^(NSURL *location,
                        NSURLResponse *response,
                        NSError *error) {
        // the image is uploaded as NSData
        UIImage *downloadedImage =
          [UIImage imageWithData:
              [NSData dataWithContentsOfURL:location]];
      // update UIImageView image to show the new file
      dispatch_async(dispatch_get_main_queue(), ^{
        // do stuff with image
        _imageWithBlock.image = downloadedImage;
      });
}];
 
// start up the task
[getImageTask resume];
Step #4 Implementing the delegate methods
We need to have our delegate implement some methods from the NSURLSessionDownloadDelegate protocol. For instance, 
we need to get notified when the download is complete:
-(void)URLSession:(NSURLSession *)session
     downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
  // see code above from completion handler
}
Here we are provided with the location that the file is downloaded to so you can use it to work with the image.

Tracking Download Progress.
To track the download progress for either task creation method, do the following:

-(void)URLSession:(NSURLSession *)session
     downloadTask:(NSURLSessionDownloadTask *)downloadTask
     didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
  NSLog(@"%f / %f", (double)totalBytesWritten,
    (double)totalBytesExpectedToWrite);
}
Step #5: When the task is finished, URLSession:downloadTask:didFinishDownloadingToURL: is called
In the case of a file download, this is when you can save the file from the temporary location to a permanent one.
  • When the download fails or is cancelled, you can get the data to resume the download.
NSURLSessionTask
Both NSURLSessionDataTask and NSURLSessionDownloadTask are derived from NSURLSessionTask, which is the
base class as illustrated below.

Image: Courtesy of Ray Wenderlick's NSURLSession Tutorial
NSURLSessionTask
This is the base class for creating session tasks, which are generally one of the following subclasses.

NSURLSessionDataTask
This task is used for issuing HTTP GET requests to pull down data from servers.
The data is returned in the form of NSData, which needs to be converted to the appropriate
XML, JSON, etc. format.

NSURLSessionDataTask *jsonData = [session dataTaskWithURL:yourNSURL
      completionHandler:^(NSData *data,
                          NSURLResponse *response,
                          NSError *error) {
        // handle NSData
}];
NSURLSessionUploadTask
This class is used to upload something to a web service using HTTP POST or PUT commands.
The delegate for the tasks also allows you to watch the network traffic while it is being 
transmitted.


Upload an image:
NSData *imageData = UIImageJPEGRepresentation(image, 0.6);
 
NSURLSessionUploadTask *uploadTask =
  [upLoadSession uploadTaskWithRequest:request
                              fromData:imageData];
The task above is created from a session and the image is uploaded as NSData. Separate methods are available for uploading using files or a stream.

NSURLSessionDownloadTask
NSURLSessionDownloadTask makes it super-easy to download files from remote service and/or pause and resume the download at will. This subclass is a little different than the other two.
  • This type of task writes directly to a temporary file.
  • During the download the session will call NSURLSessionDownload URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite: to update status information
  • When the task is finished, URLSession:downloadTask:didFinishDownloadingToURL: is called. This is when you can save the file from the temp location to a permanent one.
  • When the download fails or is cancelled you can get the data to resume the download.
  • This feature can be useful for downloading photos to your device's camera roll.
We have covered the essential sequence of method calls required for NSURLSession when using a system provided delegate.  For further thorough documentation and detailed information on the NSURLSession and associated APIs, please refer to the Apple's URL Loading System Programming Guide or Ray Wenderlick's NSURLSession Tutorial .
If you find this post helpful or want to share your experiences, feel free to send me comments here or follow me on Twitter @tasneemsayeed.  Have fun with NSURLSession Coding!

    Tuesday, March 17, 2015

    iOS: How to Send Asynchronous Requests

    Many of the applications we build often have to fetch some sort of data through the network. While there are a number of ways one could fetch the data in our iOS application and a number of networking libraries available, it is still useful to understand how NSURLConnection actually works.

    Step #1:
    Need to have your class to conform to the NSURLConnectionDelegate protocol and declare a var to store the response data

    Step #2:
    Implement the NSURLConnectionDelegate protocol methods

    Step #3:
    Create an instance of NSURLRequest and NSURLConnection to kick off the request

    In Step#1, when you class conforms to the NSURLConnectionDelegate protocol, it means that your class will need to implement all the required methods, which takes you to Step#2.
    The idea is that when you kick off the request in Step #3, you want to be notified of events that will happen such as when the response comes back, and need to handle them appropriately.


    Step #1:
    Within the class that you will be using NSURLConnection, specify in the header file that it conforms to the NSURLConnectonDelegate protocol. Also, declare an instance variable  for holding the response data.





    Step #2:
    Next, implement the NSURLConnection protocol methods

















    Step #3
    Now, we are finally ready to perform the asynchronous request.
    Let's start by creating an instance of NSURLRequest, and assign it to the URL.  Next, create an instance of a NSURLConnection and call the initWithRequest method, passing it your NSURLRequest.




    After the NSURLRequest is dispatched and the request is handled, the callback handler, didReceiveResponse will be invoked to indicate that the server has responded. Then, the callback handler, connection:didReceiveData will be invoked. This is where you will append the new data to the instance variable you declared.  In connectionDidFinishLoading callback is invoked when the request is complete and the data has been received, so you can parse the response data and do whatever you want to do with the data.  That's all there's to it!

    In the next blog post, I will cover how to send an asynchronous request using NSURLSession and Blocks!

    Wednesday, May 7, 2014

    Quick Tutorial: Implementing Your Own Delegates in Objective-C

    The delegate pattern is another simple, yet powerful design pattern. Many UI elements in iOS (i.e. UIScrollView, UITextField, UITableView,etc) use delegates to control their behavior. A delegate is an object that acts on behalf of, or in coordination with, another object when that object encounters an event in a program. The delegating object is often a responder object—that is, an object inheriting from NSResponder in AppKit or UIResponder in UIKit—that is responding to a user event. The delegate is an object that is delegated control of the user interface for that event, or is at least asked to interpret the event in an application-specific manner. For a more thorough description on delegates, refer to the Apple documentation.
    In order to implement your own custom delegate protocol, you will need to 
    1. Modify the header (.h) file for MyClass (i.e. MyClass.h)
    2. Add the @protocol delaration
    3. Add a delegate @property
    4. Declare the methods that delegates can implement.















    Next, make sure to check if the delegate is set and that it responds to the selector anytime you want to call the delegate within your implementation.









    Next, for the classes that you want to conform to your new protocol, include MyClass.h header file and delegate protocol in the @interface





    Finally, set its delegate to self somewhere and implement the delegate method




















    View more documents from tasneemsayeed.

    Tuesday, May 6, 2014

    How to Send Email Within Your iPhone Application

    This article provides a tutorial to help you send an email from inside your iPhone application using the iPhone SDK built-in APIs.
    The iPhone SDK provides the built-in MessageUI framework, which greatly simplifies the implementation of email functionality within an iOS application.

    Creating a Simple Email UI

    Create a simple app with a UI View Controller and call it the name, "SimpleEmailAppViewController". Then, add a button to the UIView by dragging it from the interface builder, and rename the button title to "Contact Us".

    When the user taps the "Contact Us" button, the app will display the email user interface.

    Making Connections to the User Interface

    In order to make the connections from the "Contact Us" button to an action, you need to select the SimpleEmailAppViewController.xib file from the Project Navigator then go to the Interface Builder. Switch to the Assistant Editor while hiding the Utility area. Once this is done, the interface and its corresponding code are displayed side by side. Next, press and hold the key and click the "Contact Us" button and
    drag it towards the "SimpleEmailAppViewController.h. As you place the pointer just below @interface and before the @end, and as you release the mouse button, you will notice a prompt that allows you to insert an outlet and action.
    Select "Action" for "Connection" and enter "sendEmail" for "name" as shown below.

    The event can be kept as "Touch Up Inside". When the user clicks the "Contact Us" button and lifts up the finger inside the button, it will result in invoking the "sendEmail" method.  Once, you click Connect to confirm the changes, Xcode automatically adds the method declaration into "SimpleEmailAppViewController.h" file.

    Implementing the Email Interface

    In "SimpleEmailAppViewController.h", implement the "MFMailComposeViewControllerDelegate" as shown below.

    In "SimpleEmailAppViewController.m", implement the "sendEmail" method. Also, add the implementation for the delegate method, "MFMailComposeViewControllerDelegate".  Note that we will also be utilizing the built-in API from the iOS SDK called "MFMailComposeViewController".
    The "MFMailComposeViewController" class provides a standard interface to allow the editing, and composing of an email message. You can use this view controller to display a standard email view within your iOS application. We populate the fields of this view with initial values including the recipient email, subject and body of the message.

    This view controller class also includes the following delegate method:
    (void) mailComposeController:(MFMailComposeViewController *)controller 
      didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error

    This method is invoked when the user cancels the operation and the mail composition interface is dismissed. The result parameter tells you the result code when the mail composition interface is dismissed. In a real-world application, the app should display any errors that may occur if the app fails to send the email message.

    Linking with the Message UI Framework

    If you try to build the application, you will notice that you will get build errors. The "MFMailComposeViewController" class is built-in within the MessageUI framework. 
    To fix the compilation problem(s), you will need to add the MessageUI framework so that it is linked properly with your application.  In the Project Navigator, select the "SimpleEmailApp" project and then select "SimpleEmailApp" target under Targets.  Then, click "Build Phases" at the top of the project editor panel. Then, click on "Link Binary With Libraries" section. 














    Next, click the "+" button and select the "MessageUI framework". After you click the "Add" button, Xcode will include the MessageUI framework. This should fix your error(s), and you can now run your application.  When you tap on the "Contact Us" button, it will display the email composition window with the pre-populated email content.

    If you find this tutorial helpful, and would like to see more of these types of tutorials, then share a comment!  Or if you have any other suggestions, do let me know as well.  And follow me on twitter (@tasneemsayeed).
    View more documents from tasneemsayeed.

    Saturday, October 26, 2013

    DevFest West 2013: Lightning Talk: Learnings, Prototypes & Use Cases on Google Glass



    According to IMS Research, the wearables market is poised to grow from 14 million devices shipped in 2011 to as many as 171 million units shipped by 2016!  According to a recent Business Insider report, "those betting big on wearable computing believe an assorted new crop of gadgets — mostly worn on the wrist or as eyewear — will become a "fifth screen," after TVs, PCs, smartphones, and tablets."

    I recently was invited to talk at the DevFest West 2013 held at the Google campus in Mountain View where I presented a Lightning Talk on "Learnings, Prototypes & Use Cases on Google Glass".
    The talk provides insights and lessons learned from innovative experiments for building innovative services for Google Glass for capturing financial data picture and for mobile payments.  It also covers a number of Glass Use-Cases as well as Glass Prototypes that we implemented across Intuit.  If you find the presentation slides below useful, then add a comment here or follow me @tasneemsayeed for future postings!


    View more documents from tasneemsayeed.

    Wednesday, July 10, 2013

    Learning on Accessibility for the iOS Platform

    According to Apple's Accessibility Guide for iOS, you should make your iPhone application accessible to VoiceOver users because:
    • It increases your user base. You've worked hard to create a great application; don’t miss the opportunity to make it available to even more users.
    • It allows people to use your application without seeing the screen. Users with visual impairments can use your application with the help of VoiceOver.
    • It helps you address accessibility guidelines. Various governing bodies create guidelines for accessibility and making your iPhone application accessible to VoiceOver users can help you meet them.
    • It's the right thing to do.
    As of iOS 3.0, Apple has included the UI Accessibility programming interface, which is a lightweight API that helps an application provide all the information VoiceOver needs to describe the user interface and help visually impaired people use the application.
    I had recently given a presentation on my Learnings on Accessibility for the iOS Platform at an internal event at Intuit, which I wanted to share with all of you.  It provides an overview on what it means to make an app accessible for the iOS platform. It also provides guidelines for making your iOS app accessible and includes an overview on the most common accessible attributes, traits and how to add Accessibility via interface builder as well as in code. It covers Accessibility Notifications, VoiceOver specific API, Accessibility Containers, and some of the best practices for Accessibility.
     
    If you find the presentation helpful in making your iOS app accessible, feel free to send me a comment!  
    Enjoy making your iOS app accessible!