A High-Level Look at NSURLSession

Though Apple introduced NSURLSession in 2013, NSURLConnection has served as such a strong networking infrastructure that there really hasn’t been a need to update it. With the upcoming release of watchOS 2 and iOS 9 in September, refreshing Personal Capital’s tech stacks seem appropriate so we can take full advantage of Apple’s latest technology offerings.

The NSURLSession API comprises of the same components as NSURLConnection (NSURLRequest, NSURLResponse, NSHTTPCookieStorage, NSURLCache and NSURLProtocol) but replaces NSURLConnection with NSURLSession, NSURLSessionConfiguration, and NSURLSessionTask.

 

NSURLSession: divide and conquer

NSURLSession introduces the concept of configuring cache, cookie, credential, and protocol policies into sessions instead of sharing these policies throughout the app. This allows you to separate network tasks into appropriate sessions as needed so changes to protocols, credentials, cookie storage, or cache storage can be localized to only the tasks in that session. This is done by initializing an NSURLSession with an NSURLSessionConfiguration. After initialization, you cannot change a session’s configuration. If you feel a need to do so, this probably means the network request or task belongs in a different session. If needed, you can override HTTP header values set in the HTTPAdditionalHeaders property of a session’s configuration by setting them in the NSURLRequest.

 

NSURLSessionConfiguration: persist/share, private, and background

NSURLSessionConfiguration has 3 types of constructors.
+ defaultSessionConfiguration returns the default configuration and defaults to using the same shared cache, cookie, and credentials storage that are familiar with NSURLConnection.
+ ephemeralSessionConfiguration returns a configuration that uses no persistent storage for cache, cookie, and credentials. This configuration would be used if you wanted to create a feature similar to private browsing.
+ backgroundSessionConfigurationWithIdentifier: returns a configuration that allows HTTP and HTTPS uploads and downloads while the app is in the background. If an upload or download is interrupted because the app is terminated by the system, the upload or download can be resumed by creating a new NSURLSessionConfiguration with the same identifier that was used for the interrupted configuration and passing that to a new NSURLSession. Interrupted tasks cannot be resumed if the app was terminated by the user.

 

NSURLSessionTask: reminds me of NSURLConnection with a completionHandler … and background support!

NSURLSessionTask is analogous to NSURLConnection because it’s the base class for handling requests for data as well as the uploading and downloading of files. NSURLSessionTask consists of three different subclasses.

  • NSURLSessionDataTask is used for making HTTP and HTTPS requests and return the server’s response as NSData in memory. An NSURLSessionTask can be constructed by providing an NSURL object or an NSURLRequest. These tasks are only supported in default and ephemeral sessions.
  • NSURLSessionUploadTask is a subclass of NSURLSessionDataTask but these tasks provide an easier way to upload content. For example, you can create an NSURLSessionUploadTask by passing an NSURLRequest with either NSData representing the body data of the request or an NSURL object for the URL of the file to upload. These tasks are allowed in background sessions and provide callbacks to the session’s delegate as data is uploading. Since these tasks are allowed in background sessions, you can technically create an NSURLSessionUploadTask (pass nil for the body data) instead of an NSURLSessionDataTask if you really require the task to continue in the background.
  • NSURLSessionDownloadTask is a task that directly writes the server’s response data to a temporary file. After completion, the app needs to move the temporary file to an appropriate place. These tasks can run in any type of session.

Instead of allocating an NSURLSessionTask on it’s own, tasks are instantiated by an NSURLSession object. An NSURLSessionTask can be constructed with and without a completionHandler. If a completionHandler is provided, it will be executed after the request is completed on the delegate queue. For NSURLSessionDataTask and NSURLSessionUploadTask tasks, the completionHandler will return the NSData and NSURLResponse object returned by the server or an NSError object if an error occurred. The completionHandler for an NSURLSessionDownloadTask task returns the location of the downloaded file as an NSURL object, the NSURLResponse from the server, or an NSError object if an error occurred.

 

Delegates: why to not construct with a completionHandler

You may be wondering why you would ever create an NSURLSessionTask without a completionHandler. If you require finer control over the progress of an NSURLSessionTask, you need to provide a delegate. If you provide a delegate and also provide a completionHandler, you will notice that none of the callbacks related to progress are called. (You will still get URLSession:task:didReceiveChallenge:completionHandler:.) If you want to receive all of the callbacks, you need to construct your task without a completionHandler. The combination of NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, and NSURLDataDownloadDelegate cover the delegate methods that NSURLConnectionDelegate and NSURLConnectionDataDelegate provided for NSURLConnection. Each of these delegates are well documented so there’s no need to go over them in this article. One thing to note, though, is that both NSURLSessionDelegate and NSURLSessionTaskDelegate provide callbacks for authentication challenges. The callback for NSURLSessionDelegate handles authentication challenges at the connection level (NSURLAuthenticationMethodNTLM, NSURLAuthenticationMethodNegotiate, NSURLAuthenticationMethodClientCertificate, and NSURLAuthenticationMethodServerTrust). If URLSession:didReceiveChallenge:completionHandler: is not implemented at the session level, the callback at the task level is called. URLSession:task:didReceiveChallenge:completionHandler: will additionally handle authentication challenges at the request level.

 

Further reading

All of the information mentioned in this article can be further studied in the NSURLSession Class Reference from the iOS Developer Library (https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSession_class/).

We are Growing our Engineering Team!

This is your opportunity to be a disruptor in the financial industry while creating a service that serves families and improves lives.

What sets us apart is the way we use both data aggregation and machine learning technologies along with certified financial advisors to model a family’s financial life. No one has ever had the data, the technology and the people to do what we do: combine the power of an abstract computer model with the expertise of certified financial advisors to help families understand their current financial situation and help them optimize it for the next stages of their lives.

The amazing thing about working at Personal Capital is that when I leave the office each evening, I’m pumped with more energy, enthusiasm and optimism than when I came in. And that’s because I get to build a noble service with great people; it can’t get any better than that. Every day I work with the most talented engineers that I have ever worked with, building sophisticated services that empower thousands of American families to take control of their finances.

We are looking for curious engineers. We are looking for thinkers and doers. You need to be smart and build smart products. You need to be ambitious. This is not an easy job. You will need to wear multiple hats, work with many unknowns, travel many unpaved roads to tackle large-scale problems. But it will be your finest work and creation, and an amazing engineering team is here to collaborate with you and support you.

Here are our current open positions:

 

 

Mobile Development: Testing for Multiple Device Configurations

All Android developers should have at least 1 “old” device running OS 2.3.3 and a current “popular” device. Ideally, one should also have a current device that is considered “maxed out” on specs. A company should additionally have the latest “Google” device (currently the Nexus series), and an HTC, Sony, and Samsung device. (These manufacturers are mentioned because of popularity and/or significant differences not found when developing on other devices.) Additionally, OS 4.2, 4.3, and 4.4, though minor OS increments, offer differences that should be considered.

Though development for iPhone/iPad is more forgiving given the fewer configurations, it still offers challenges. For example, if you are developing on a Mac running OS X Mavericks with a version of Xcode above 5.0 for a product that still needs to support iOS 5.x, you will need a physical device because the iOS 5.x simulator isn’t available for that development configuration.

If testing mobile websites, the configurations can be endless.

At Apps World 2014, Perfecto Mobile (http://www.perfectomobile.com) introduced me to mobile cloud device testing. Their product offers access to real devices (not emulators or simulators) connected to actual carriers physically hosted at one of their sites around the world.

The concept of mobile cloud device testing allows the ability to test on a multitude of configurations of devices, locations/timezones, carriers, and operating systems.

Beyond access to multiple devices, Perfecto Mobile offers automation testing across these platforms via scripts written in Java. I wasn’t able to personally delve as far as I wanted into these automation tests, the recording feature, or the object mapper before my trial ran out, but the demo at Apps World gave me the impression it behaves similar to Xcode’s Automation instrument but expanded to all devices.  The scripts enable your team to target certain device configurations and automatically launch, execute the given tests, clean and close the devices, and export the test results to your team.  I wish I could say more because it looked really promising but without actual usage, I can only mention what I viewed during the demo.

It’s impossible to cover every configuration during native Android application development, but after a release, for all platforms, if your product is experiencing issues and a crash report doesn’t reveal enough, mobile cloud device testing offers the a real option for true coverage.

Below is a listing of some features of interest Perfecto Mobile offers:
- Access to real devices connected to actual carriers (not emulators or simulators) physically hosted at one of Perfecto’s sites around the world. Since these are real devices, you can dial numbers, make calls, send text messages, and install apps.
- UI for devices available displays availability, manufacturer, model, os + version, location, network, phone number, device id, firmware, resolution.
- Ability to open multiple devices at the same time.
- Requests for devices and configurations not available are responded to in real-time.
- Ability to take screenshots and record sessions to save and/or share results with others.
- Ability to share the device screen in real-time with your team.
- Ability to collect information for a device such as battery level, CPU, memory, and network activity.
- Export of device logs.
- Beta of MobileCloud for Jenkins plug-in that allows running scripts on actual cloud devices after a build so you can see reports on a single device after a build (multiple devices is not available yet).

AppWorlds 2014

Overall Impression

Last year there were a lot of companies that concentrate on analytics and HTML5 while this year the trends seem to be more diverse. The companies that caught my eye were

  • Jumio (http://www.jumio.com/netswipe/). Their Netswipe product provides real time Credit/Debit Card number recognition. It’s a card scan by optical card recognition (vs magnetic strip swipe)
  • Appsee (http://www.appsee.com). This company concentrates on A/B testing and they have given me a comprehensive demo of what A/B testing is and what you can do with it
  • Moxtra (www.moxtra.com). This company presented MeetSDK which is an SDK for embedding online meeting experience into custom apps. The experience is similar to Goto meeting or Google hangouts, where in addition to video chat there is a screen sharing capability.

Attended talks

Use A/B testing to build better apps (Chris Beauchamp from Kii)

A/B testing seems to be the next evolutionary step for just collecting metrics. The idea is to control provide optional data, screen presentations and screen flows for real-time users and then collect metrics. A/B testing requires a slightly different development approach and thus most of the talk was broken down into pros and cons of A/B testing.

Pros:

  • Features can be turned on / off instantaneously. A real life example given by Chris describing how he accidentally released one of the features intended for demo purposes and the feature was only taken down 2 weeks later after AppStore approved patch release.
  • Better segmentation. If currently with KISSMetrics we collect data on ALL of the users, A/B testing platforms can only target certain segments of their user base without disrupting the core users.

Cons:

  • QA and dev overhead. When we release support with various flow and display options we must QA these beforehand. With iOS7 and autoupdates it seems like an alternative could be just having each bi-weekly release as an experiment

Agile development for mobile (Crashlytics and Twitter)

Quick and short list of takeaways

  • Releasing a new version of your mobile app bi-weekly is acceptable amongst users. More frequent updates are not.
  • Dogfooding. Using your company employees as beta testers.  While your app is awaiting approval in the app store, you can have a local dogfood release to your fellow coworkers. So, once the app is in the App Store , you might already know the top 10 issues with it and start working on a patch release immediately.
  • In the experience of Twitter mobile dev top most frequent bugs compose 90% of the issues.

Reusing Web Modules with RequireJS

why

  • Our application contains several modules that uniquely addresses a key aspect of wealth management. eg: Investment checkup, Net worth, etc. The application brings together various such aspects to present a comprehensive one-stop wealth management tool to the user.
  • How-ever each user’s needs are unique and so are the motivations to use our application. So we wanted to build landing pages that ties a user’s need to a module thus providing more context and motivation to use the module and eventually our entire offerings.
  • We went native for our mobile presence to provide great user experience and that has served us well. How-ever they are few modules of our application that are self contained with simpler ui design and fewer interactions with rest of the application. We wanted to embed such modules in our native app and determine if we could still deliver a great seamless user experience.

what

  • Build “stand-alone” versions of our web modules.
  • Publish the module with a unique url that will be used to embed it in other apps.

how

We use Requirejs as our module loader and its optimization tool to package a module and its dependencies into single units for production use. The module definition would define all its dependencies. During development phase, all the dependencies are loaded as required. How-ever in production mode, all the dependencies are packaged into a single file along with the module code to minimize our http calls and optimize load times. For eg:

A simple module definition would be as follows:

define([
 'jquery'
 , 'underscore'
 ], function($, _){

 var foo = {};
 // module code
 return foo;
});

And we reference the above module as follows:

<script data-main="scripts/foo" src="scripts/require.js"></script>

But most real-world application will have several modules and would share considerable number of framework libraries (jquery, underscore, backbone and etc) and utility libraries. And our application is no exception. So we defined a common module that would require all the common libs and in turn require this as part of our main module. The sub modules would still continue to list of all its required dependencies, but as part of the build process, we exclude them for optimization and to prevent from any shared lib being re-initialized/reset.

When the application starts, it loads the main module first and there after required modules as user navigates the application. Following is a gist of our build file is defined:

({
 modules: [
 { 
 name: 'app_main'
 }
 , {
 name: 'foo'
 , exclude:[
 'jquery'
 , 'underscore'
 , 'backbone'
 , 'services'
 , 'hbs'
 ]
 }
 ]
})

app_main will be loaded at the start of the application and if a user navigated to a foo module, only then the application will load foo. This worked great for us in keeping our main module lean as we kept adding more features (modules) until the requirement of reusing some of the modules in other apps/clients (mobile).

Fortunately for us, this did not involve lot of work and more importantly did not result in any redundant code. All we had to do was to define another main module that would include our common module and foo module. That is it. We had to refactor our common module a little bit to include only the core libs. Other shared libs were loaded as part of the main module (app_main). This way we did not load any libs that were not needed for foo module.

({
 modules: [
 { 
 name: 'app_main'
 }
 , {
 name: 'foo'
 , exclude:[
 'jquery'
 , 'underscore'
 , 'backbone'
 , 'services'
 , 'hbs'
 ]
 }
 , {
 name: 'app_foo'
 }
 ]
})
//app_main.
require(['common'], function (common) {
 require(['main']);
});

//app_foo
require(['common'], function (common) {
 require(['foo']);
});

This was just not fortune. From the very start of this app development, we not only aimed for modular code, but also to have an ability to extend any module to work by itself. Our entire MV* stack was architected that way and we are glad the returns are truly amazing.

We have a SPA that is comprised of several modules and at any time, any module can be extended to its own SPA app with minimal effort and no codes changes to the modules themselves. Thanks to the amazing requirejs optimization tool and a little foresight.

More details on how we use requirejs and its optimization tools are presented here.

reads

http://addyosmani.github.com/backbone-fundamentals

http://requirejs.org/docs/optimization.html

http://requirejs.org/docs/optimization.html#wholemultipage

http://requirejs.org/