iOS Api Client: soluzioni a confronto
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

iOS Api Client: soluzioni a confronto

on

  • 830 views

Slides della sessione su iOS Api Client: soluzioni a confronto, tenuta da Massimo Oliviero e Francesco Sinopoli alla WhyMCA 2012.

Slides della sessione su iOS Api Client: soluzioni a confronto, tenuta da Massimo Oliviero e Francesco Sinopoli alla WhyMCA 2012.
http://www.whymca.org/intervento/ios-api-client-soluzioni-confronto

-----


Abbiamo sognato un giorno in cui REST diventerà lo standard per tutti i servizi web, le API saranno progettate e documentate come quelle di Twitter, tutti capiranno il significato di concetti come Risorsa, URI e HATEOAS e il mondo sarà per sempre riconoscente a Roy Fielding. Abbiamo sognato … Poi ci siamo svegliati e siamo andati al lavoro. Puntualmente abbiamo trovato il seguente scenario: applicazione critica, progetto in scadenza, API server inviolabili.

Vi ricordate quella battuta in Apollo 13: come incastrare un tubo tondo in un boccaporto quadrato? In questa sessione mostreremo alcune pratiche, prodotte dalle nostre Lesson Learned, per realizzare un client iOS chiamato ad interagire con API remote ponendo l'accento sull'architettura software.

Statistics

Views

Total Views
830
Views on SlideShare
722
Embed Views
108

Actions

Likes
0
Downloads
11
Comments
0

2 Embeds 108

http://pragmamark.org 102
http://next.pragmamark.org 6

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

iOS Api Client: soluzioni a confronto Presentation Transcript

  • 1. iOS Api Client Soluzioni a confronto Massimo Oliviero - Cappery S.r.l. Francesco Sinopoli - Tiltap S.r.l.Monday, May 28, 12
  • 2. Chi siamo  Massimo Oliviero http://www.massimooliviero.net - @maxoly  Co-founder & CEO di Cappery www.cappery.com  Co-founder di # pragma mark www.pragmamark.orgMonday, May 28, 12
  • 3. Francesco Sinopoli TILTAP Superpartes Innovation Campus | H-FARM @ondadurto francescosinopoli@hotmail.com http://it.linkedin.com/in/francescosinopoli co-founder di # pragma mark www.pragmamark.orgMonday, May 28, 12
  • 4. Disclaimer • Non è una sessione su REST • Non è una sessione su sulle API Server • Non vuole essere una sessione esaurienteMonday, May 28, 12
  • 5. Agenda • Architettura • Framework custom • Framework terze parti: REST KitMonday, May 28, 12
  • 6. ScenariMonday, May 28, 12
  • 7. Scenari • Scenario A Server Api non REST(ful)Monday, May 28, 12
  • 8. Scenari • Scenario A Server Api non REST(ful) • Scenario B Server API REST(ful)Monday, May 28, 12
  • 9. SoluzioniMonday, May 28, 12
  • 10. Soluzioni A. Easy (w lo spaghetti code!)Monday, May 28, 12
  • 11. Soluzioni A. Easy (w lo spaghetti code!) B. Framework customMonday, May 28, 12
  • 12. Soluzioni A. Easy (w lo spaghetti code!) B. Framework custom C. Framework di terze partiMonday, May 28, 12
  • 13. Un nuovo progettoMonday, May 28, 12
  • 14. Un nuovo progettoMonday, May 28, 12
  • 15. Un nuovo progetto • App per la N.A.S.A.Monday, May 28, 12
  • 16. Un nuovo progetto • App per la N.A.S.A. • Con tre view (Lista pianeti + Lista rover sul pianeta + dettaglio rover)Monday, May 28, 12
  • 17. Un nuovo progetto • App per la N.A.S.A. • Con tre view (Lista pianeti + Lista rover sul pianeta + dettaglio rover) • Il dettaglio deve mostrare alcuni parametri del rover (es. Opportunity su Marte)Monday, May 28, 12
  • 18. Un nuovo progetto • App per la N.A.S.A. • Con tre view (Lista pianeti + Lista rover sul pianeta + dettaglio rover) • Il dettaglio deve mostrare alcuni parametri del rover (es. Opportunity su Marte) • Lettura dei dati tramite server API della NASAMonday, May 28, 12
  • 19. Un nuovo progetto • App per la N.A.S.A. • Con tre view (Lista pianeti + Lista rover sul pianeta + dettaglio rover) • Il dettaglio deve mostrare alcuni parametri del rover (es. Opportunity su Marte) • Lettura dei dati tramite server API della NASA • 10 gg/uMonday, May 28, 12
  • 20. Dominio 1 n 1 n Planet Rover Cam 1 1 GeoMonday, May 28, 12
  • 21. Server • REQUEST GET /opportuniy_get_info.aspx? id=11A1&planet=mars • RESPONSE content-type: text/htmlMonday, May 28, 12
  • 22. Server • REQUEST GET /opportuniy_get_info.aspx? id=11A1&planet=mars • RESPONSE content-type: text/htmlMonday, May 28, 12
  • 23. Non ci REST che piang!Monday, May 28, 12
  • 24. Non ci REST che piang!Monday, May 28, 12
  • 25. Non ci REST che piang! Accettiamo la sfida!Monday, May 28, 12
  • 26. Soluzione B sviluppiamo un framework customMonday, May 28, 12
  • 27. Framework custom Domande • Cosa vuol dire sviluppare un framework custom? • Quando sviluppare un framework custom? • Quali sono i vantaggi? • Quali sono gli svantaggi?Monday, May 28, 12
  • 28. Architettura un approccio gradualeMonday, May 28, 12
  • 29. LayersMonday, May 28, 12
  • 30. Layers ViewMonday, May 28, 12
  • 31. Layers View ControllerMonday, May 28, 12
  • 32. Layers View Controller Network LayerMonday, May 28, 12
  • 33. Layers View Controller Domain Model Layer Network LayerMonday, May 28, 12
  • 34. Layers View Controller Domain Data Model Layer Layer Network LayerMonday, May 28, 12
  • 35. Layers View Controller Domain Business Data Model Layer Layer Layer Network LayerMonday, May 28, 12
  • 36. Layers View Controller Domain Business Data Model Layer Layer Layer Network LayerMonday, May 28, 12
  • 37. Example Code  PMStarterKit Pragma Mark Starter Kit https://github.com/pragmamark/PMStarterKit  PMTouch Pragma Mark iOS General Purpose Library https://github.com/pragmamark/PMTouchMonday, May 28, 12
  • 38. Network Layer il primo mattoncino della nostra architetturaMonday, May 28, 12
  • 39. Network Layer Cosa deve fare • Gestire URL e risorse • Gestire request e response • Gestire proxy & authentication • Gestire la cache (Cache-Control & ETag)Monday, May 28, 12
  • 40. RequestMonday, May 28, 12
  • 41. Request Network Layer RequestMonday, May 28, 12
  • 42. Request Cosa deve fare • Incapsulare una singola chiamata di rete ad una risorsa (URL) specifica • Gestire i verbi HTTP (GET, POST, PUT, DELETE..) • Gestire i parametriMonday, May 28, 12
  • 43. NSURLConnection - (void)viewDidLoad { [super viewDidLoad]; static NSString *url = @"http://..../?p1=v1&p2=v2"; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; self.connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; } ..... - (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data - (void)connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)error - (void)connectionDidFinishLoading:(NSURLConnection *)theConnection - (void)connection:(NSURLConnection *)theConnection didReceiveResponse: (NSURLResponse *)responseMonday, May 28, 12
  • 44. Monday, May 28, 12
  • 45. NSURLConnectionMonday, May 28, 12
  • 46. NSURLConnection ProMonday, May 28, 12
  • 47. NSURLConnection Pro • NativoMonday, May 28, 12
  • 48. NSURLConnection Pro • Nativo • DocumentatoMonday, May 28, 12
  • 49. NSURLConnection Pro • Nativo • Documentato • FlessibileMonday, May 28, 12
  • 50. NSURLConnection Pro • Nativo • Documentato • FlessibileMonday, May 28, 12
  • 51. NSURLConnection Pro • Nativo • Documentato • FlessibileMonday, May 28, 12
  • 52. NSURLConnection Pro Contro • Nativo • Documentato • FlessibileMonday, May 28, 12
  • 53. NSURLConnection Pro Contro • Nativo • Povero • Documentato • FlessibileMonday, May 28, 12
  • 54. NSURLConnection Pro Contro • Nativo • Povero • Documentato • Verboso • FlessibileMonday, May 28, 12
  • 55. Alternative • ASIHTTPRequest https://github.com/pokeb/asi-http-request/tree • AFNetwork (by Gowalla) https://github.com/AFNetworking/AFNetworking • MKNetworkKit https://github.com/MugunthKumar/MKNetworkKitMonday, May 28, 12
  • 56. ASIHTTPRequest • Mac OS X & iPhone • Synchronous & asynchronous requests • Basic, Digest e NTLM authentication • Cache control and ETag support • Throttling bandwidthMonday, May 28, 12
  • 57. ASIHTTPRequest - (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [NSURL URLWithString:@"http://www.apple.com"]; ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:url]; self.request = request; [request release]; [self.request setDelegate:self]; [self.request startAsynchronous]; } - (void)requestStarted:(ASIHTTPRequest *)request { } - (void)requestFinished:(ASIHTTPRequest *)request { } - (void)requestFailed:(ASIHTTPRequest *)request { }Monday, May 28, 12
  • 58. AFNetworking • HTTP Requests (cancelled, suspended / resumed) • Authenticating requests with HTTP Basic credentials or an OAuth token • Blocks • feature-rich APIsMonday, May 28, 12
  • 59. AFNetworkig NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/ public_timeline.json"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { NSLog(@"Public Timeline: %@", JSON); } failure:nil]; [operation start];Monday, May 28, 12
  • 60. Response Network LayerMonday, May 28, 12
  • 61. Response Network LayerMonday, May 28, 12
  • 62. Response Network Layer RequestMonday, May 28, 12
  • 63. Response Network Layer Request ResponseMonday, May 28, 12
  • 64. Response Network Layer Request ResponseMonday, May 28, 12
  • 65. Response Network Layer Request ResponseMonday, May 28, 12
  • 66. Response Network Layer Request ResponseMonday, May 28, 12
  • 67. Response Cosa deve fare • Incapsulare l’HTTP Response (Header, Status code etc.) • Payload (HTTP Content body) • Result (JSON > NSArray/NSDictionary etc.) • ErrorMonday, May 28, 12
  • 68. Response @interface PMTResponse : NSObject { PMTRequest *_request; NSString *_contentBody; NSError *_error; NSObject *_result; } @property (nonatomic, retain, readonly) PMTRequest *request; @property (nonatomic, retain, readonly) NSString *contentBody; @property (nonatomic, retain, readonly) NSError *error; @property (nonatomic, retain, readonly) NSObject *result; - (id)initWithRequest:(PMTRequest *)request; - (id)initWithRequest:(PMTRequest *)request result:(NSObject *)result; - (id)initWithRequest:(PMTRequest *)request result:(NSObject *)result error: (NSError *)error; @endMonday, May 28, 12
  • 69. Parser Cosa deve fare • Trasformare stringhe o dati binari in strutture dati native (es. da JSon a NSArray).Monday, May 28, 12
  • 70. JSON Parser Alcune librerie • NSJSONSerialization • JSONKit • SBJson Benckmarks https://github.com/samsoffes/json-benchmarksMonday, May 28, 12
  • 71. XML Parser Alcune librerie • NSXMLParser (modalità SAX) • libxml2 (C Library SAX e DOM) • TBXML (DOM) • TouchXML (NSXML DOM) • KissXML (NSXML DOM) • TinyXML (C Library DOM)Monday, May 28, 12
  • 72. Cache Network LayerMonday, May 28, 12
  • 73. Cache Network LayerMonday, May 28, 12
  • 74. Cache Network Layer RequestMonday, May 28, 12
  • 75. Cache Network Layer Request ResponseMonday, May 28, 12
  • 76. Cache Network Layer Request Response CacheMonday, May 28, 12
  • 77. Cache Network Layer Request Response CacheMonday, May 28, 12
  • 78. Cache Network Layer Request Response CacheMonday, May 28, 12
  • 79. Cache Cosa deve fare • Gestire la direttiva cache-control • Gestire la direttiva ETag • Storage policy: per session o permanentMonday, May 28, 12
  • 80. Cache • A cosa serve A gestire la cache • Quando utilizzarla Quando il server lo prevede e lo gestisce in modo efficente ed efficace con le direttive HTTP. • Perché utilizzarla Perché diminuisce il traffico di rete e di conseguenza aumenta la responsività dell’app.Monday, May 28, 12
  • 81. Client Network LayerMonday, May 28, 12
  • 82. Client Network LayerMonday, May 28, 12
  • 83. Client Network Layer RequestMonday, May 28, 12
  • 84. Client Network Layer Request ResponseMonday, May 28, 12
  • 85. Client Network Layer Request Response CacheMonday, May 28, 12
  • 86. Client Network Layer Request Response Cache ClientMonday, May 28, 12
  • 87. Client Network Layer Request Response Cache ClientMonday, May 28, 12
  • 88. Client Cosa deve fare • Gestire ambienti diversi (produzione, sviluppo, stage, etc.) • Aprire e chiudere tunnel ssh o vpn • Gestire l’autenticazioneMonday, May 28, 12
  • 89. Client • A cosa serve Ad incapsulare le request in ambienti specifici. • Quando utilizzarlo Quando si gestiscono ambienti diversi (stage, prod. etc.) o quando si utilizzano tunnel SSH o VPN. • Perché utilizzarlo Per isolare la gestione di queste specifiche funzionalità.Monday, May 28, 12
  • 90. Client @interface PMTClient : NSObject { NSURL *_baseUrl; NSString *_username; NSString *_password; } @property (nonatomic, retain, readonly) NSURL *baseUrl; @property (nonatomic, copy) NSString *username; @property (nonatomic, copy) NSString *password; - (id)initWithBaseURL:(NSURL *)baseUrl; - (id)initWithBaseURL:(NSURL *)baseUrl username:(NSString *)username password: (NSString *)password; - (PMTRequest *)createRequest:(NSString *)stringUrl delegate: (id<PMTRequestDelegate>)delegate;Monday, May 28, 12
  • 91. Network Manager Network LayerMonday, May 28, 12
  • 92. Network Manager Network Layer RequestMonday, May 28, 12
  • 93. Network Manager Network Layer Request ResponseMonday, May 28, 12
  • 94. Network Manager Network Layer Request Response CacheMonday, May 28, 12
  • 95. Network Manager Network Layer Request Response Cache ClientMonday, May 28, 12
  • 96. Network Manager Network Layer Network Manager Request Response Cache ClientMonday, May 28, 12
  • 97. Network Manager Cosa deve fare • Creare ed eseguire le request tramite il client • Gestire le code di request • Gestire il suspend e il resumeMonday, May 28, 12
  • 98. Network Manager • A cosa serve A governare il network layer. • Quando utilizzarlo Quando si vuole disaccopiare e gestire attività complesse come le code, etc. • Perché utilizzarlo Disaccoppia il view controller dall’implementazione di rete e di conseguenza aumenta la manutenibilità del codice.Monday, May 28, 12
  • 99. Network Manager @interface PMTNetworkManager : NSObject { SPKRequestQueue *_requestQueue; } @property (nonatomic, retain, readonly) PMTRequestQueue *requestQueue; @property (nonatomic, assing) BOOL enableSuspendResume; - (PMTRequest *)requestAdd:(NSString *)request params:(NSDictionary *)params - (PMTRequest *)requestAdd:(NSString *)request params:(NSDictionary *)params queue:(NSString *)queueName; - (void)addQueue:(NSString *)queueName; - (void)requestsStart; - (void)requestsStop; @endMonday, May 28, 12
  • 100. Network Layer Quando utilizzare un networking framework? • SEMPRE, quando possibile evitare di utilizzare direttamente NSURLConnection. Non ha senso. • Framework come ASIHTTPRequest o AFNetworking semplicano troppo la vita per non essere utilizzati. (Twitter e Facebook docet)Monday, May 28, 12
  • 101. Network LayerMonday, May 28, 12
  • 102. Network Layer In conclusione • HTTP Request & Response • Tunneling SSH/VPN • Ambienti (stage, produzione etc.) • Cache (HTTP) • Network ManagerMonday, May 28, 12
  • 103. Network Layer In conclusione • HTTP Request & Response • Tunneling SSH/VPN • Ambienti (stage, produzione etc.) • Cache (HTTP) • Network ManagerMonday, May 28, 12
  • 104. One more thing...Monday, May 28, 12
  • 105. One more thing...Monday, May 28, 12
  • 106. One more thing... “Oltre che leggere l’app deve poter anche inviare dei comandi al rover!”Monday, May 28, 12
  • 107. Domain Model Layer modelliamo il nostro businessMonday, May 28, 12
  • 108. Domain Model Layer Cosa deve fare • Gestire il dato (entità e relazioni) • Gestire il comportamento • Convertire il dato da una forma ad un’altraMonday, May 28, 12
  • 109. Model Domain Model LayerMonday, May 28, 12
  • 110. Model Domain Model LayerMonday, May 28, 12
  • 111. Model Domain Model Layer ModelMonday, May 28, 12
  • 112. Model Domain Model Layer ModelMonday, May 28, 12
  • 113. Model Cosa deve fare • Rappresentare l’informazione attraverso l’ausilio di una struttura dati nativa o custom • Possibilmente oltre al dato dovrebbe incorporare anche il comportamentoMonday, May 28, 12
  • 114. NSDictionary & NSArray NSDictionary *element = [self.elements objectAtIndex:indexPath.row]; cell.textLabel.text = [element objectForKey:@"name"]; cell.detailTextLabel.text = [element objectForKey:@"description"];Monday, May 28, 12
  • 115. NSObject @interface PMSKPlanet : NSObject @property (nonatomic, copy, readonly) NSString *name; @property (nonatomic, retain, readonly) PMSKGalaxy *galaxy; - (id)initWithName:(NSString *)name galaxy:(PMSKGalaxy *)galaxy; @end @interface PMSKGalaxy : NSObject @property (nonatomic, copy, readonly) NSString *name; @property (nonatomic, retain, readonly) NSArray *planets; - (id)initWithName:(NSString *)name; @endMonday, May 28, 12
  • 116. Mapper Domain Model LayerMonday, May 28, 12
  • 117. Mapper Domain Model LayerMonday, May 28, 12
  • 118. Mapper Domain Model Layer ModelMonday, May 28, 12
  • 119. Mapper Domain Model Layer Model MapperMonday, May 28, 12
  • 120. Mapper Cosa deve fare • Definire le regole di traformazione da una struttura dati ad un’altra (es. NSArray to NSObject) • Gestire le regole e fornirle su richiesta attraverso un sistema centralizzatoMonday, May 28, 12
  • 121. Object Mapper @interface PMTObjectMapper : NSObject - (void)mapKey:(NSString *)mapKey toProperty:(NSString *)property; + (PMTObjectMapper *)mapperForClass:(Class)class; @end PMTObjectMapper *mapper = [PMTObjectMapper mapperForClass:[PMSKGalaxy class]]; [mapper mapKey:@"planet_name" toProperty:@"name"]; [mapper mapKey:@"solar_distance" toProperty:@"solarDistance"];Monday, May 28, 12
  • 122. Domain ModelMonday, May 28, 12
  • 123. Domain Model In conclusione • Entità e relazioni • MappaturaMonday, May 28, 12
  • 124. Domain Model In conclusione • Entità e relazioni • MappaturaMonday, May 28, 12
  • 125. One more “little” thingMonday, May 28, 12
  • 126. One more “little” thingMonday, May 28, 12
  • 127. One more “little” thing “L’applicazione deve funzionare anche OFFLINE”Monday, May 28, 12
  • 128. Data Layer persistiamo i nostri datiMonday, May 28, 12
  • 129. Data Layer Cosa deve fare • Persistere le informazioni • Recuperare le informazioniMonday, May 28, 12
  • 130. Store Data LayerMonday, May 28, 12
  • 131. Store Data LayerMonday, May 28, 12
  • 132. Store Data Layer StoreMonday, May 28, 12
  • 133. Store Data Layer StoreMonday, May 28, 12
  • 134. File system • File system NSCoding, NSKeyedArchiver, NSKeyedUnarchiver • Plist NSDictionary, NSArray, NSFileManagerMonday, May 28, 12
  • 135. Relational • FMDB (Objective-C wrapper around SQLite) https://github.com/ccgus/fmdb • CoreData (object graph & persistence framework) http://developer.apple.com/library/mac/ #documentation/cocoa/conceptual/coredata/ cdprogrammingguide.htmlMonday, May 28, 12
  • 136. Manager Data LayerMonday, May 28, 12
  • 137. Manager Data LayerMonday, May 28, 12
  • 138. Manager Data Layer StoreMonday, May 28, 12
  • 139. Manager Data Layer Store ManagerMonday, May 28, 12
  • 140. Manager Cosa deve fare • Fornire un’interfaccia di accesso ai dati persistiti • Fornire strumenti di interrogazioneMonday, May 28, 12
  • 141. Conclusioni e quindi?Monday, May 28, 12
  • 142. Framework custom Layer Quando Network Layer SEMPRE Domain Model Leggere e scrivere Data Layer OfflineMonday, May 28, 12
  • 143. Framework customMonday, May 28, 12
  • 144. Framework custom VantaggiMonday, May 28, 12
  • 145. Framework custom Vantaggi • Know-howMonday, May 28, 12
  • 146. Framework custom Vantaggi • Know-how • ModulareMonday, May 28, 12
  • 147. Framework custom Vantaggi • Know-how • Modulare • Flessibile (Business)Monday, May 28, 12
  • 148. Framework custom Vantaggi Svantaggi • Know-how • Modulare • Flessibile (Business)Monday, May 28, 12
  • 149. Framework custom Vantaggi Svantaggi • Know-how • Tempo (Costi) • Modulare • Flessibile (Business)Monday, May 28, 12
  • 150. Framework custom Vantaggi Svantaggi • Know-how • Tempo (Costi) • Modulare • Skill • Flessibile (Business)Monday, May 28, 12
  • 151. Framework custom Vantaggi Svantaggi • Know-how • Tempo (Costi) • Modulare • Skill • Flessibile (Business) • DeclinatoMonday, May 28, 12
  • 152. Soluzione C API + Dominio di Business =Monday, May 28, 12
  • 153. RestKit Che cosa è ? Restkit è un framework Objective-C per iOS che ha lo scopo di facilitare linterazione con i web-service.Monday, May 28, 12
  • 154. RestKit Che cosa fa ? HTTP PROTOCOL REST SOAP XML ENCODE PARSER CODE ACTIVE RECORD PATTERN MAPPING CACHE STRATEGY SQLMonday, May 28, 12
  • 155. Network Layer Obiettivo “Ha la funzione di costruire e consegnare le richieste HTTP e processare le risposte che arrivano dal server remoto” Come raggiunge l’obiettivo? Attraverso tre attori principali RKClient RKRequest RKResponseMonday, May 28, 12
  • 156. Network Layer Base URL RKClient Http headers - Type Authentication RKClient AppMonday, May 28, 12
  • 157. Network Layer Base URL RKClient Http headers - Type Authentication Base URL RKClient Http headers - Type Authentication RKClient AppMonday, May 28, 12
  • 158. Network Layer RKClient RKRequest RKResponse #import "AppDelegate.h" #import <RestKit/RestKit.h> @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions { RKClient *client = [RKClient clientWithBaseURL:@"https://api.pragma-mark.org/ sampleQuiz"]; ... Da qui in poi avremo disponibile [RKClient sharedClient]Monday, May 28, 12
  • 159. Network Layer Esempio: invio richiesta e visualizzazione risposta #import <UIKit/UIKit.h> #import <RestKit/RestKit.h> @interface MyViewController : UIViewController<RKRequestDelegate> {... Una volta configurato un client possiamo inviare e processare richieste HTTP attraverso esso. @implementation MyViewController ... #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; resource path [[RKClient sharedClient] get:@"/collections/questions" delegate:self]; } #pragma mark - Restkit delegate - (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response { NSLog(@"Loaded payload: %@ with code %i", [response bodyAsString], [response statusCode]); } -(void)request:(RKRequest*)request didFailLoadWithError:(NSError*)error { NSLog(@"Error %@",[error localizedDescription]); }Monday, May 28, 12
  • 160. Network Layer Siamo in grado di comunicare con un web service remoto, inviare richieste e processare risposte, ? Web Service payloadMonday, May 28, 12
  • 161. Object Mapping Quando ne abbiamo bisogno e che cosa è? Quando si ha necessità, non solo di scambiare dati, ma di rappresentare oggetti. E’ un sistema che ci permette di trasformare le risposte JSON/XML in oggetti di dominio locali. Salendo di astrazione: è un sistema che si occupa di trasformare i dati da un formato ad un altro. Punto di forza di RestKitMonday, May 28, 12
  • 162. Object Mapping RKObjectManager RKObjectMapping RKObjectMapper RKObjectMappingProvider Le operazioni di mapping sono eseguite: •Quando carichiamo un risorsa remota tramite un’istanza di RKObjectManager •Quando un oggetto locale è inviato al backend per essere processatoMonday, May 28, 12
  • 163. Object Mapping Il protagonista principale di questo layer è RKObjectManager “RKObjectManager è la classe che si occupa della trasformazione dei dati contenuti nel payload in oggetti” RKObjectManager RKClient AppMonday, May 28, 12
  • 164. Object Mapping Esempio: caricare oggetti remoti in oggetti locali Obiettivo: vogliamo recuperare una collection di question dal web serviceMonday, May 28, 12
  • 165. Object Mapping Esempio: caricare oggetti remoti in oggetti locali Il web service ritorna qualcosa di simile a... { “questions”: [ { "body" : "Che cosa si intende per scope creep?", "correctIdAnswer" : 1, "identifier" : 1 }, { "body" : "Che differenza c’è tra lead e lag?", "correctIdAnswer" : 2, "identifier" : 2 } ] }Monday, May 28, 12
  • 166. Object Mapping Esempio: caricare oggetti remoti in oggetti locali ...lato client, questi dati sono rappresentati da una classe @interface Question : NSObject @property (nonatomic, copy) NSNumber* identifier; @property (nonatomic, copy) NSString* body; @property (nonatomic, copy) NSNumber* correctIdAnswer; @endMonday, May 28, 12
  • 167. Object Mapping Un esempio: caricare oggetti remoti in oggetti locali Configuriamo RestKit Definiamo un mapping per la classeRKObjectManager* objectManager = [RKObjectManager QuestionobjectManagerWithBaseURL:@"https://api.pragmamark.org/quiz"];RKObjectMapping* questionMapping = [RKObjectMapping mappingForClass:[Question class]];[questionMapping mapKeyPath:@"identifier" toAttribute:@"identifier"];[questionMapping mapKeyPath:@"body" toAttribute:@"body"];[questionMapping mapKeyPath:@"correctIdAnswer"toAttribute:@"correctIdAnswer"];[objectManager.mappingProvider setMapping:questionMappingforKeyPath:@"questions"]; Istruiamo il mapping provider ad usare questionMapping se incontra un @”questions” key pathMonday, May 28, 12
  • 168. Object Mapping Un esempio: caricare oggetti remoti in oggetti locali Carichiamo gli oggetti[[RKObjectManager sharedManager] loadObjectsAtResourcePath:@”/questions" delegate:self]; ...i dati vengono recuperati, parserizzati e assegnati agli oggetti locali - (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects: (NSArray*)objects { La classe deve implementare RKObjectLoaderDelegate ! NSLog(@"Loaded statuses: %@", objects); }Monday, May 28, 12
  • 169. Object Mapping Siamo in grado di Caricare comunicare con un rappresentazioni di web service oggetti remoti remoto, inviare nella nostra App e richieste e mapparli in oggeti processare risposte localiMonday, May 28, 12
  • 170. Object Mapping JSON XML ... Server payload Inviare oggetti al server (Serialization)Monday, May 28, 12
  • 171. Object Mapping Serialization? Un’altra operazione di mapping. RKObjectSerializer RKParser [{ "body" : "Che cosa si intende per scope creep?", Mapping Encoder "correctIdAnswer" : 1, "identifier" : 1 attributi e Request }, relazioni { "body" : "Che differenza Local Domain Intermediate c’è tra lead e lag?", Backend Objects Dictionary "correctIdAnswer" : 2, "identifier" : 2 System (NSMutableDictionary) JSON (XML, URL Form Encode...)Monday, May 28, 12
  • 172. Object Mapping Un esempio: inviare oggetti locale al server remoto Configuriamo RestKit [[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions" forMethod:RKRequestMethodPOST]; Lo stesso mapping definito prima è utilizzo per [[RKObjectManager sharedManager] serializzare la classe setSerializationMIMEType:RKMIMETypeJSON]; RKObjectMapping* questionSerializationMapping = [questionMapping inverseMapping]; [[RKObjectManager sharedManager].mappingProvider setSerializationMapping:questionSerializationMapping forClass: [Question class]]; Istruiamo il mapping provider ad usare questionSerializationMappingMonday, May 28, 12
  • 173. Object Mapping Un esempio: inviare oggetti locale al server remoto Creiamo l’oggetto // Create a new Question and POST it to the server Question* question = [Question new]; question.body = @"Cosa si intende per approccio agile ad un progetto?"; question.identifier = [NSNumber numberWithInt: 3]; Inviamo la richiesta...[[RKObjectManager sharedManager] postObject:question delegate:self]; RestKit sa che deve ...recuperiamo la risposta dal server serializzare quando - (void)objectLoader:(RKObjectLoader*)objectLoader esegue un POST o un didLoadObjects:(NSArray*)objects PUT { ! NSLog(@"Loaded statuses: %@", objects); }Monday, May 28, 12
  • 174. Routing Ovvero, dove vivono gli oggetti? Per interagire con un web service è necessario sapere dove gli oggetti risiedono. RestKit offre un sistema di routing capace di generare resource path per un oggetto. /qu 4 est ns/65 ion s/7 esti o 89 /qu RKObjectRouter Routing System /qu e sti on s/1 23 RKObjectRouter registra un mapping tra una classe del dominio e un resource path per uno specifico metodo HTTP.Monday, May 28, 12
  • 175. Routing Ovvero, dove vivono gli oggetti? GET [[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions/(idpk)" forMethod:RKRequestMethodGET]; POST [[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions" forMethod:RKRequestMethodPOST]; PUT [[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions/(idpk)" forMethod:RKRequestMethodPUT]; DELETE [[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions/(idpk)" forMethod:RKRequestMethodDELETE];Monday, May 28, 12
  • 176. Routing Un esempio: inviare un oggetto al server Definiamo default route che sarà usato per tutti gli HTTP Inizializziamo il nostro route... verbs (GET, POST, PUT e DELETE) [[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions/(identifier)"]; [[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions" forMethod:RKRequestMethodPOST]; registriamo uno specifico route per il verbo POSTMonday, May 28, 12
  • 177. Routing Un esempio: inviare oggetti locale al server remoto RKObjectRouter è quindi utilizzato per generare resource path quando utilizziamo getObject, deleteObject, postObject e putObject. POST// Nel setup dell’App abbiamo già definito i mapping per questa classeQuestion* question = [Question new];question.body = @"Cosa si intende per approccio agile ad un progetto?";[[RKObjectManager sharedManager] postObject:question delegate:self]; “/questions”Monday, May 28, 12
  • 178. Routing Un esempio: inviare oggetti locale al server remoto RKObjectRouter è quindi utilizzato per generare resource path quando utilizziamo getObject, deleteObject, postObject e putObject. PUT Question *question = [Question new]; question.body = @"Che cosa si intende per scope creep?"; question.identifier = [NSNumber numberWithInt: 3]; [[RKObjectManager sharedManager] putObject:question delegate:self]; “/questions/3”Monday, May 28, 12
  • 179. Routing Un esempio: inviare oggetti locale al server remoto RKObjectRouter è quindi utilizzato per generare resource path quando utilizziamo getObject, deleteObject, postObject e putObject. DELETEQuestion *question = [Question new];question.identifier = [NSNumber numberWithInt: 3];[[RKObjectManager sharedManager] deleteObject:question delegate:self]; “/questions/3”Monday, May 28, 12
  • 180. Offline :| Core Data Integration A questo punto, cosa siamo in grado di fare? Interagire con il Rappresentare Modificare e web service le risorse inviare oggetti remoto remote in locali al backend localeMonday, May 28, 12
  • 181. Offline :| Core Data Integration Assenza di connettività?Monday, May 28, 12
  • 182. Offline :) Core Data Integration Assenza di connettività? Persistiamo i dati in locale con Core DataMonday, May 28, 12
  • 183. Offline Core Data Integration Vediamo come fare passo dopo passo. RKManagedObjectStore RKManagedObjectMapping Setup RestKit RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:@”http://pragmamark.org]; objectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@”Quiz.sqlite]; 1 Indicare lo storeMonday, May 28, 12
  • 184. Offline Core Data Integration Vediamo come fare passo dopo passo. 2 Mapping Utilizzare RKManagedObjectMappingRKManagedObjectMapping* questionMapping = [RKManagedObjectMappingmappingForClass:[Question class]]; Questo permette al 3 Mapper di discriminare traquestionMapping.primaryKeyAttribute = @"identifier"; oggetti nuovi, aggiornati o eliminati[questionMapping mapKeyPath:@"identifier" toAttribute:@"identifier"];[questionMapping mapKeyPath:@"body" toAttribute:@"body"];[questionMapping mapKeyPath:@"correctIdAnswer"toAttribute:@"correctIdAnswer"];[objectManager.mappingProvider setMapping:questionMappingforKeyPath:@"questions"];Monday, May 28, 12
  • 185. Offline Core Data Integration 4 Il modello persistente deve ereditare da NSManagedObject @interface Question : NSManagedObject @property (nonatomic, copy) NSNumber* identifier; @property (nonatomic, copy) NSString* body; @property (nonatomic, copy) NSNumber* correctIdAnswer; @endMonday, May 28, 12
  • 186. Offline Core Data Integration @implementation Question @implementation Question @synthesize identifier; @dynamic identifier; @synthesize body; @dynamic body; @synthesize correctIdAnswer; @dynamic correctIdAnswer; 5 @end @end @dynamic vs @synthesizeMonday, May 28, 12
  • 187. Offline Core Data Integration 6 Data Model Data Model resource 2012-05-20 12:03:20.921 WhyMCA[1060:fb03] *** Terminating app due to uncaught exception NSInternalInconsistencyException, reason: Cannot initialize an RKManagedObjectMapping without an entity. Maybe you want RKObjectMapping instead?Monday, May 28, 12
  • 188. Offline Core Data Integration Ora che succede? Transient {questions: [ objects { "body" : "Che cosa si intende per scope creep?", "correctIdAnswer" : 1, "identifier" : 1 }, Local Domains { "body" : "Che differenza mapping Objects c’è tra lead e lag?", "correctIdAnswer" : 2, "identifier" : 2 Persistent }] } objects JSON (XML, Form URL Encode...)Monday, May 28, 12
  • 189. Offline Core Data Integration Un esempio: chiedere i dati al server Dopo aver fatto richieste al server... [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@”/questions" delegate:self]; ...i dati sono recuperati, parserizzati e assegnati agli oggetti locali - (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects { ! NSLog(@"Loaded questions: %@", objects); }Monday, May 28, 12
  • 190. Offline Core Data Integration Un esempio: chiedere i dati al server 2012-05-13 16:01:03.478 WhyMCA[9935:fb03] Loaded questions: ( "<Question: 0x83a1bd0>", "<Question: 0x83a57d0>" ) 2012-05-20 12:29:00.757 WhyMCA [1499:fb03] Loaded questions: ( "<Question: 0x6b921b0> (entity: Question; id: 0x6e704e0 <x- coredata://62C52FE3-86E9-4FD0-9BA8-FAE16839477E/Question/p1> ; data: <fault>)", "<Question: 0x6b8f090> (entity: Question; id: 0x6e707a0 <x- coredata://62C52FE3-86E9-4FD0-9BA8-FAE16839477E/Question/p5> ; data: <fault>)", }Monday, May 28, 12
  • 191. Offline Core Data Integration Un esempio: chiedere i dati al server Impostiamo la nostra tecnica if ([[RKObjectManager sharedManager] isOnline]) { [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/ questions" delegate:self]; } else { NSArray *questions = [Question allObjects]; } Alternative? •Implementare di RKManagedObjectCache protocol •Utilizzare RKRequestCache •Database seedingMonday, May 28, 12
  • 192. In practice RestKit Mapping & CoreData “Non sempre le risposte del web service sono come ce le aspettiamo”(Anonimo) Team Mobile Team Server-sideMonday, May 28, 12
  • 193. In practice RestKit Mapping & CoreData Elaboriamo un pò il nostro model •Aggiungiamo l’entità Answer •Question e Answer sono in relazione molti a molti •L’identificativo di Question è in un oggetto nidificato •Nell’elenco delle question manca la key Path @”questions”Monday, May 28, 12
  • 194. In practice RestKit Mapping & CoreData Dove è la key @“questions” ? {[ Come identifichiamo il contenuto? {"_id": {         "$identifier": "4faf69fee4b0895a3ed9b1ff"     },{ “questions”: [     "correctIdAnswer": 1, { "identifier" : 1     "body": "Quale è il significato del termine "body" : "Che cosa si intende per scope creep?", lead?", "correctIdAnswer" : 1,     "answers": [ },         {             "identifier": "3", { "identifier" : 2             "body": "risposta B" "body" : "Che differenza c’è tra lead e lag?",         }, "correctIdAnswer" : 2,         { }]             "identifier": "1",}             "body": "risposta A"         }     ] }, {...Monday, May 28, 12
  • 195. In practice RestKit Mapping & CoreData @interface Question : NSManagedObject @property (nonatomic, copy) NSString* identifier; @property (nonatomic, copy) NSString* body; @property (nonatomic, copy) NSNumber* correctIdAnswer; @property (nonatomic, retain) NSSet* answers; @end @interface Answer : NSManagedObject @property (nonatomic, copy) NSString* identifier; @property (nonatomic, copy) NSString* body; @property (nonatomic, retain) NSSet* questions; @endMonday, May 28, 12
  • 196. In practice RestKit Mapping & CoreData//MappingRKManagedObjectMapping* questionMapping = [RKManagedObjectMappingmappingForClass:[Question class]];questionMapping.primaryKeyAttribute = @"identifier";[questionMapping mapKeyPath:@"_id.$identifier" toAttribute:@"identifier"];[questionMapping mapKeyPath:@"body" toAttribute:@"body"];[questionMapping mapKeyPath:@"correctIdAnswer"toAttribute:@"correctIdAnswer"];RKManagedObjectMapping* answerMapping = [RKManagedObjectMappingmappingForClass:[Answer class]];[answerMapping setPrimaryKeyAttribute:@"identifier"];[answerMapping mapKeyPath:@"identifier" toAttribute:@"identifier"];[answerMapping mapKeyPath:@"body" toAttribute:@"body"];[questionMapping mapKeyPath:@"answers" toRelationship:@"answers"withMapping:answerMapping];[objectManager.mappingProvider addObjectMapping:questionMapping];Monday, May 28, 12
  • 197. In practice RestKit Mapping & CoreData Effettuiamo la richiesta al server... RKObjectMapping *questionMapping = [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:[Question class]]; [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@”/ questions" objectMapping:questionMapping delegate:self];Monday, May 28, 12
  • 198. In practice RestKit Mapping & CoreData Possiamo costruire un mapping dinamicamente... [[RKObjectManager sharedManager] postObject:question delegate:self block:^(RKObjectLoader* loader) { loader.objectMapping = [RKObjectMapping mappingForClass: [Question class] block:^(RKObjectMapping* mapping) { [mapping mapAttributes:@"identifier", @"body", nil]; }]; }];Monday, May 28, 12
  • 199. Le code i retroscena. Inviare richieste e processare risposte: RKRequest RKResponse RKClient PayloadMonday, May 28, 12
  • 200. Le code i retroscena. Inviare richieste e processare risposte: RKRequest RKResponse RKClient Payload RKRequestQueueMonday, May 28, 12
  • 201. Le code i retroscena. Inviare richieste e processare risposte: Cosa succede quando inviamo una richiesta con RKRequest? [RKClient sharedClient].requestQueue //[[RKClient sharedClient].requestQueue addRequest:loader]; RKRequestQueue è utilizzato anche per: •rilevare connettività •limitare le richieste concorrenti •eliminare richieste per un determinato delegato [[RKClient sharedClient].requestQueue cancelRequestsWithDelegate:delegate];Monday, May 28, 12
  • 202. Le code i retroscena. Inviare richieste e processare risposte: Possiamo usarle per: •Raggruppare le chiamate per la paginazione, per la ricerca, per il workflow di acquisto, etc.. e utilizzare la sharedQueue per soddisfare la user action. •Effettuare il download di un’entità “complessa”. Ad esempio: ipotizziamo una Guida, entità del dominio, rappresentata da un grafo di oggetti contenente le sue proprietà e le sue relazioni ma che fa riferimento a diversi asset (audio, fotografie, tiles per le mappa offline) attraverso percorsi esterni.Monday, May 28, 12
  • 203. Le code Inviare richieste e processare risposte: i retroscena. Creare una coda... RKRequestQueue *queue = [RKRequestQueue requestQueueWithName:nameQueue]; queue.concurrentRequestsLimit = 5;Monday, May 28, 12
  • 204. Le code Inviare richieste e processare risposte: i retroscena. Aggiungere richieste... NSString *resourcePath = [NSString stringWithFormat:@"%@%@/ %i",kAPIAddress,kAPI_AUDIO_GET,[identifier intValue]]; RKRequest *request = [RKRequest requestWithURL:[NSURL URLWithString:resourcePath] delegate:self]; request.authenticationType = RKRequestAuthenticationTypeHTTPBasic; request.username = [RKClient sharedClient].username; request.password = [RKClient sharedClient].password; [queue addRequest:request] [queue start];Monday, May 28, 12
  • 205. Le code Inviare richieste e processare risposte: i retroscena. Svuotare la coda... //verifica prima se esiste la queue BOOL existsQueue = [RKRequestQueue requestQueueExistsWithName:nameQueue]; if (existsQueue) { RKRequestQueue *queue = [RKRequestQueue requestQueueWithName:nameQueue]; NSLog(@"Elimino richieste in coda %i",[queue count]); [queue cancelAllRequests]; NSLog(@"Richieste in coda %i",[queue count]); }Monday, May 28, 12
  • 206. Conclusioni e quindi?Monday, May 28, 12
  • 207. “Buon senso”Monday, May 28, 12