Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Effective Network Programming in iOS 7

Effective Network Programming in iOS 7

Presented at Mobile Developer Summit Oct 11th in Bangalore, India

Ben Scheirman

October 11, 2013
Tweet

More Decks by Ben Scheirman

Other Decks in Programming

Transcript

  1. What we’ll cover w /463-4FTTJPO#BTJDT w -*7&$0%*/( XJTINFMVDL w "'/FUXPSLJOH

    w )551$BDIJOH w $BDIJOH1BUUFSOT w "1*%FTJHO5JQT Wednesday, October 9, 13
  2. NSURLConnection Invented for Safari ~2000, made public in 2003 Poor

    separation of settings, config, cache Now replaced by NSURLSession classes Wednesday, October 9, 13
  3. NSURLConnection Invented for Safari ~2000, made public in 2003 Poor

    separation of settings, config, cache Now replaced by NSURLSession classes Wednesday, October 9, 13
  4. NSURLSession Still use NSURLRequest Configurable Container (isolation w/ 3rd party

    libraries) Improved auth Rich Callbacks Wednesday, October 9, 13
  5. NSURLSession NSURLSession Interface for issuing network calls against a server

    Likely use case: 1 session per API Wednesday, October 9, 13
  6. NSURLSessionDelegate Delegate methods for a session: Used for connect level

    authentication challenges NTLM, Kerberos, Client certificates - URLSession:didBecomeInvalidWithError: - URLSession:didReceiveChallenge:completionHandler: Wednesday, October 9, 13
  7. NSURLSessionTaskDelegate Delegate methods for a request: Only need to implement

    for fine-grained control - URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler: - URLSession:task:didReceiveChallenge:completionHandler: - URLSession:task:needNewBodyStream: - URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend: - URLSession:task:didCompleteWithError: Wednesday, October 9, 13
  8. NSURLSessionDataTaskDelegate Delegate methods for a data request: Only need to

    implement for fine-grained control - URLSession:dataTask:didReceiveChallenge:completionHandler: - URLSession:dataTask:didBecomeDownloadTask: - URLSession:dataTask:didReceiveData: - URLSession:dataTask:willCacheResponse:completionHandler: Wednesday, October 9, 13
  9. Have you ever seen this? NSURL *imageUrl = [NSURL URLWithString:

    @”http://i.imgur.com/kwpjYwQ.jpg”]; NSData *imageData = [NSData dataWithContentsOfURL:imageUrl]; UIImage *image = [UIImage imageWithData:imageData]; [imageView setImage:image]; Wednesday, October 9, 13
  10. Have you ever seen this? NSURL *imageUrl = [NSURL URLWithString:

    @”http://i.imgur.com/kwpjYwQ.jpg”]; NSData *imageData = [NSData dataWithContentsOfURL:imageUrl]; UIImage *image = [UIImage imageWithData:imageData]; [imageView setImage:image]; WRONG Wednesday, October 9, 13
  11. Have you ever seen this? NSURL *imageUrl = [NSURL URLWithString:

    @”http://i.imgur.com/kwpjYwQ.jpg”]; NSData *imageData = [NSData dataWithContentsOfURL:imageUrl]; UIImage *image = [UIImage imageWithData:imageData]; [imageView setImage:image]; Wednesday, October 9, 13
  12. What constitutes an error? • Connection failed • Timeouts •

    Host invalid • Bad URL • Too many redirects • ... dozens more (check URL Loading System Error Codes) Wednesday, October 9, 13
  13. Installation gem install cocoapods Podfile pod install platform :ios, "7.0"

    pod 'AFNetworking', '2.0' Wednesday, October 9, 13
  14. Installation gem install cocoapods Podfile pod install platform :ios, "7.0"

    pod 'AFNetworking', '2.0' Wednesday, October 9, 13
  15. Installation Podfile pod install platform :ios, "6.0" pod 'AFNetworking' platform

    :ios, "7.0" pod 'AFNetworking', '2.0' gem install cocoapods Wednesday, October 9, 13
  16. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] Wednesday, October 9, 13
  17. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; Wednesday, October 9, 13
  18. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; manager.responseSerializer = [[AFJSONSerializer alloc] init]; Wednesday, October 9, 13
  19. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; manager.responseSerializer = [[AFJSONSerializer alloc] init]; [manager GET:url parameters:nil completion:^(NSURLSessionDataTask *task, Wednesday, October 9, 13
  20. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; manager.responseSerializer = [[AFJSONSerializer alloc] init]; [manager GET:url parameters:nil completion:^(NSURLSessionDataTask *task, id responseObject) { Wednesday, October 9, 13
  21. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; manager.responseSerializer = [[AFJSONSerializer alloc] init]; [manager GET:url parameters:nil completion:^(NSURLSessionDataTask *task, id responseObject) { // handle success Wednesday, October 9, 13
  22. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; manager.responseSerializer = [[AFJSONSerializer alloc] init]; [manager GET:url parameters:nil completion:^(NSURLSessionDataTask *task, id responseObject) { // handle success } failure:^(NSURLSessionDataTask *task, NSError *error) { Wednesday, October 9, 13
  23. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; manager.responseSerializer = [[AFJSONSerializer alloc] init]; [manager GET:url parameters:nil completion:^(NSURLSessionDataTask *task, id responseObject) { // handle success } failure:^(NSURLSessionDataTask *task, NSError *error) { // handle failure Wednesday, October 9, 13
  24. Usage NSURL *url = [NSURL URLWithString:@”http://google.com”]; NSURLSessionConfiguration *config = [NSURLSessionConfiguration

    defaultConfiguration]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:config]; manager.responseSerializer = [[AFJSONSerializer alloc] init]; [manager GET:url parameters:nil completion:^(NSURLSessionDataTask *task, id responseObject) { // handle success } failure:^(NSURLSessionDataTask *task, NSError *error) { // handle failure }]; Wednesday, October 9, 13
  25. HTTP Status Code Cheat Sheet 1xx - Not Used 2xx

    - Thumbs Up 3xx - It's over there 4xx - You messed up 5xx - We messed up Wednesday, October 9, 13
  26. HTTP Caching Client Server HTTP/1.1 200 OK Content-Type: application/json Content-Length:

    37142 Etag:“e6482391249374127ca94128” Cache-Control:max-age=60, public Date:Sun, 21 Oct 2012 16:15:37 GET /customer/152.json HTTP 1.1 Host: example.com Wednesday, October 9, 13
  27. HTTP Caching GET /customer/152.json HTTP 1.1 Host: example.com Client Server

    HTTP/1.1 200 OK Content-Type: application/json Content-Length: 37142 Etag:“e6482391249374127ca94128” Cache-Control:max-age=60, public Date:Sun, 21 Oct 2012 16:15:37 Wednesday, October 9, 13
  28. HTTP Caching GET /customer/152.json HTTP 1.1 Host: example.com Client Server

    HTTP/1.1 200 OK Content-Type: application/json Content-Length: 37142 Etag:“e6482391249374127ca94128” Cache-Control:max-age=60, public Date:Sun, 21 Oct 2012 16:15:37 Wednesday, October 9, 13
  29. HTTP Caching GET /customer/152.json HTTP 1.1 Host: example.com Client Server

    HTTP/1.1 200 OK Content-Type: application/json Content-Length: 37142 Etag:“e6482391249374127ca94128” Cache-Control:max-age=60, public Date:Sun, 21 Oct 2012 16:15:37 Wednesday, October 9, 13
  30. Leveraging Etag on the client GET /customer/152.json HTTP 1.1 Host:

    example.com If-None-Match:“e6482391249374127ca94128” Client Server Wednesday, October 9, 13
  31. Leveraging Etag on the client GET /customer/152.json HTTP 1.1 Host:

    example.com If-None-Match:“e6482391249374127ca94128” Client Server HTTP/1.1 304 Not Modified < no response body > Wednesday, October 9, 13
  32. Leveraging Modified Date GET /customer/152.json HTTP 1.1 Host: example.com If-Modified-Since:

    <date> Client Server HTTP/1.1 304 Not Modified < no response body > Wednesday, October 9, 13
  33. Etag/Last Modified on the Server def show @band = Band.find(params[:id])

    fresh_when(:etag => @band, Wednesday, October 9, 13
  34. Etag/Last Modified on the Server def show @band = Band.find(params[:id])

    fresh_when(:etag => @band, :last_modified => @band, Wednesday, October 9, 13
  35. Etag/Last Modified on the Server def show @band = Band.find(params[:id])

    fresh_when(:etag => @band, :last_modified => @band, :public => true) Wednesday, October 9, 13
  36. Etag/Last Modified on the Server def show @band = Band.find(params[:id])

    fresh_when(:etag => @band, :last_modified => @band, :public => true) expires_in 10.minutes, :public => true Wednesday, October 9, 13
  37. Etag/Last Modified on the Server def show @band = Band.find(params[:id])

    fresh_when(:etag => @band, :last_modified => @band, :public => true) expires_in 10.minutes, :public => true end Wednesday, October 9, 13
  38. Etag/Last Modified on the Server def show @band = Band.find(params[:id])

    fresh_when(:etag => @band, :last_modified => @band, :public => true) expires_in 10.minutes, :public => true end Note: server still does a db query, but doesn’t render a template Saves on rendering & bandwidth for response transfer Wednesday, October 9, 13
  39. Reverse-Proxy Cache FTW Server Cache-Control: max-age: 600 Varnish / Squid

    / Nginx Cache-Control: max-age: 600 Wednesday, October 9, 13
  40. Reverse-Proxy Cache FTW Server Cache-Control: max-age: 600 Varnish / Squid

    / Nginx Cache-Control: max-age: 600 Wednesday, October 9, 13
  41. Reverse-Proxy Cache FTW Server Cache-Control: max-age: 600 Cache-Control: max-age: 600

    Varnish / Squid / Nginx Cache-Control: max-age: 600 Wednesday, October 9, 13
  42. Leverage Cache-Control? HTTP/1.1 200 OK Content-Type: application/json Content-Length: 37142 Etag:“e6482391249374127ca94128”

    Cache-Control:max-age=9999999999, public Date:Sun, 21 Oct 2012 16:15:37 GMT Wednesday, October 9, 13
  43. Pros / Cons of Cache-Control Client doesn’t wait for response

    Server spends no resources But, clients may render stale data Wednesday, October 9, 13
  44. Pros / Cons of Etag / IMS Server skips rendering

    Miniscule data transfer Appears instantaneous* But, server still doing a db query Wednesday, October 9, 13
  45. Reason about your data • List of US States •

    User’s Profile • Customer’s Order • Activity Timeline • Yesterday’s stats Wednesday, October 9, 13
  46. Caching w/ NSURLSession Leverages NSURLCache already Use default session configuration

    or customize cache settings Use ephemeral configuration to disable caching Wednesday, October 9, 13
  47. Caching w/ NSURLSession Customize if needed NSURLCache *cache = [[NSURLCache

    alloc] initWithMemoryCapacity:1024*1024*10 diskCapacity:1024*1024*50 diskPath:nil]; [sessionConfiguration setURLCache:cache]; Wednesday, October 9, 13
  48. Switcheroo View Controller API Client Coordinator get data start request

    (cached data) HTTP GET Wednesday, October 9, 13
  49. Switcheroo View Controller API Client Coordinator get data start request

    (cached data) HTTP GET Wednesday, October 9, 13
  50. Switcheroo View Controller API Client Coordinator get data start request

    (cached data) HTTP GET 200 OK Wednesday, October 9, 13
  51. Switcheroo View Controller API Client Coordinator get data start request

    (cached data) HTTP GET 200 OK (parsed response) Wednesday, October 9, 13
  52. Switcheroo View Controller API Client Coordinator get data start request

    (cached data) HTTP GET 200 OK (parsed response) update cache Wednesday, October 9, 13
  53. Switcheroo View Controller API Client Coordinator get data start request

    (cached data) HTTP GET 200 OK (parsed response) (parsed response) update cache Wednesday, October 9, 13
  54. API Design Tips Send OS Version, App Version, and Device

    Name as headers Device Name OS Version App Version Wednesday, October 9, 13
  55. API Design Tips Have a way to notify clients to

    upgrade (even force) Wednesday, October 9, 13
  56. API Design Tips • Techniques for permeating deletes • Valid

    ID Check • Client requests changes, server returns a set of new records, changed records, and deleted record ids Wednesday, October 9, 13