Sei sulla pagina 1di 207

iOS Api Client

Soluzioni a confronto

Massimo Oliviero - Cappery S.r.l. Francesco Sinopoli - Tiltap S.r.l.


Monday, May 28, 12

Chi siamo
Massimo Oliviero http://www.massimooliviero.net - @maxoly Co-founder & CEO di Cappery www.cappery.com Co-founder di # pragma mark www.pragmamark.org

Monday, May 28, 12

TILTAP Superpartes Innovation Campus | H-FARM

Francesco Sinopoli

@ondadurto francescosinopoli@hotmail.com http://it.linkedin.com/in/francescosinopoli

co-founder di # pragma mark www.pragmamark.org

Monday, May 28, 12

Disclaimer
Non una sessione su REST Non una sessione su sulle API Server Non vuole essere una sessione esauriente

Monday, May 28, 12

Agenda
Architettura Framework custom Framework terze parti: REST Kit

Monday, May 28, 12

Scenari

Monday, May 28, 12

Scenari
Scenario A

Server Api non REST(ful)

Monday, May 28, 12

Scenari
Scenario A Scenario B

Server Api non REST(ful) Server API REST(ful)

Monday, May 28, 12

Soluzioni

Monday, May 28, 12

Soluzioni
A. Easy (w lo spaghetti code!)

Monday, May 28, 12

Soluzioni
A. Easy (w lo spaghetti code!) B. Framework custom

Monday, May 28, 12

Soluzioni
A. Easy (w lo spaghetti code!) B. Framework custom C. Framework di terze parti

Monday, May 28, 12

Un nuovo progetto

Monday, May 28, 12

Un nuovo progetto

Monday, May 28, 12

Un nuovo progetto

App per la N.A.S.A.

Monday, May 28, 12

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

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

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

Monday, May 28, 12

Un nuovo progetto

Monday, May 28, 12

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/u

Dominio
Planet
1 n

Rover
1 1

Cam

Geo

Monday, May 28, 12

Server

REQUEST GET /opportuniy_get_info.aspx? id=11A1&planet=mars RESPONSE content-type: text/html

Monday, May 28, 12

Server

REQUEST GET /opportuniy_get_info.aspx? id=11A1&planet=mars RESPONSE content-type: text/html

Monday, May 28, 12

Non ci REST che piang!

Monday, May 28, 12

Non ci REST che piang!

Monday, May 28, 12

Non ci REST che piang!

Accettiamo la sda!

Monday, May 28, 12

Soluzione B
sviluppiamo un framework custom

Monday, May 28, 12

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

Architettura
un approccio graduale

Monday, May 28, 12

Layers

Monday, May 28, 12

Layers
View

Monday, May 28, 12

Layers
View Controller

Monday, May 28, 12

Layers
View Controller

Network Layer

Monday, May 28, 12

Layers
View Controller Domain Model Layer Network Layer

Monday, May 28, 12

Layers
View Controller Domain Model Layer Network Layer Data Layer

Monday, May 28, 12

Layers
View Controller Business Layer Domain Model Layer Data Layer

Network Layer

Monday, May 28, 12

Layers
View Controller Business Layer Domain Model Layer Data Layer

Network Layer

Monday, May 28, 12

Example Code
PMStarterKit Pragma Mark Starter Kit https://github.com/pragmamark/PMStarterKit PMTouch Pragma Mark iOS General Purpose Library https://github.com/pragmamark/PMTouch

Monday, May 28, 12

Network Layer
il primo mattoncino della nostra architettura

Monday, May 28, 12

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

Request

Monday, May 28, 12

Request
Network Layer

Request

Monday, May 28, 12

Request
Cosa deve fare

Incapsulare una singola chiamata di rete ad una


risorsa (URL) specica

Gestire i verbi HTTP (GET, POST, PUT, DELETE..) Gestire i parametri

Monday, May 28, 12

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 *)data - (void)connection:(NSURLConnection *)theConnection *)error - (void)connectionDidFinishLoading:(NSURLConnection - (void)connection:(NSURLConnection *)theConnection (NSURLResponse *)response didReceiveData:(NSData didFailWithError:(NSError *)theConnection didReceiveResponse:

Monday, May 28, 12

Monday, May 28, 12

NSURLConnection

Monday, May 28, 12

NSURLConnection
Pro

Monday, May 28, 12

NSURLConnection
Pro

Nativo

Monday, May 28, 12

NSURLConnection
Pro

Nativo Documentato

Monday, May 28, 12

NSURLConnection
Pro

Nativo Documentato Flessibile

Monday, May 28, 12

NSURLConnection
Pro

Nativo Documentato Flessibile

Monday, May 28, 12

NSURLConnection
Pro

Nativo Documentato Flessibile

Monday, May 28, 12

NSURLConnection
Pro Contro

Nativo Documentato Flessibile

Monday, May 28, 12

NSURLConnection
Pro Contro

Nativo Documentato Flessibile

Povero

Monday, May 28, 12

NSURLConnection
Pro Contro

Nativo Documentato Flessibile

Povero Verboso

Monday, May 28, 12

Alternative
ASIHTTPRequest MKNetworkKit
https://github.com/pokeb/asi-http-request/tree https://github.com/AFNetworking/AFNetworking https://github.com/MugunthKumar/MKNetworkKit

AFNetwork (by Gowalla)

Monday, May 28, 12

ASIHTTPRequest
Mac OS X & iPhone Synchronous & asynchronous requests Basic, Digest e NTLM authentication Cache control and ETag support Throttling bandwidth
Monday, May 28, 12

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

AFNetworking
HTTP Requests (cancelled, suspended / resumed) Authenticating requests with HTTP Basic
credentials or an OAuth token

Blocks feature-rich APIs

Monday, May 28, 12

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

Response
Network Layer

Monday, May 28, 12

Response
Network Layer

Monday, May 28, 12

Response
Network Layer

Request

Monday, May 28, 12

Response
Network Layer

Request

Response

Monday, May 28, 12

Response
Network Layer

Request

Response

Monday, May 28, 12

Response
Network Layer

Request

Response

Monday, May 28, 12

Response
Network Layer

Request

Response

Monday, May 28, 12

Response
Cosa deve fare

Incapsulare lHTTP Response


(Header, Status code etc.)

Payload (HTTP Content body) Result (JSON > NSArray/NSDictionary etc.) Error
Monday, May 28, 12

Response
@interface PMTResponse : NSObject { PMTRequest *_request; NSString *_contentBody; NSError *_error; NSObject *_result; } @property @property @property @property (nonatomic, (nonatomic, (nonatomic, (nonatomic, retain, retain, retain, retain, readonly) readonly) readonly) readonly) PMTRequest *request; NSString *contentBody; NSError *error; NSObject *result;

- (id)initWithRequest:(PMTRequest *)request; - (id)initWithRequest:(PMTRequest *)request result:(NSObject *)result; - (id)initWithRequest:(PMTRequest *)request result:(NSObject *)result error: (NSError *)error; @end

Monday, May 28, 12

Parser
Cosa deve fare

Trasformare stringhe o dati binari in strutture


dati native (es. da JSon a NSArray).

Monday, May 28, 12

JSON Parser
Alcune librerie

NSJSONSerialization JSONKit SBJson


Benckmarks https://github.com/samsoffes/json-benchmarks

Monday, May 28, 12

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

Cache
Network Layer

Monday, May 28, 12

Cache
Network Layer

Monday, May 28, 12

Cache
Network Layer

Request

Monday, May 28, 12

Cache
Network Layer

Request

Response

Monday, May 28, 12

Cache
Network Layer

Request

Response

Cache

Monday, May 28, 12

Cache
Network Layer

Request

Response

Cache

Monday, May 28, 12

Cache
Network Layer

Request

Response

Cache

Monday, May 28, 12

Cache
Cosa deve fare

Gestire la direttiva cache-control Gestire la direttiva ETag Storage policy: per session o permanent

Monday, May 28, 12

Cache
A cosa serve
A gestire la cache Quando il server lo prevede e lo gestisce in modo efcente ed efcace con le direttive HTTP. Perch diminuisce il trafco di rete e di conseguenza aumenta la responsivit dellapp.

Quando utilizzarla Perch utilizzarla

Monday, May 28, 12

Client
Network Layer

Monday, May 28, 12

Client
Network Layer

Monday, May 28, 12

Client
Network Layer

Request

Monday, May 28, 12

Client
Network Layer

Request

Response

Monday, May 28, 12

Client
Network Layer

Request

Response

Cache

Monday, May 28, 12

Client
Network Layer

Request

Response

Cache

Client

Monday, May 28, 12

Client
Network Layer

Request

Response

Cache

Client

Monday, May 28, 12

Client
Cosa deve fare

Gestire ambienti diversi (produzione, sviluppo,


stage, etc.)

Aprire e chiudere tunnel ssh o vpn Gestire lautenticazione

Monday, May 28, 12

Client
A cosa serve
Ad incapsulare le request in ambienti specici. Quando si gestiscono ambienti diversi (stage, prod. etc.) o quando si utilizzano tunnel SSH o VPN. Per isolare la gestione di queste speciche funzionalit.

Quando utilizzarlo Perch utilizzarlo

Monday, May 28, 12

Client
@interface PMTClient : NSObject { NSURL *_baseUrl; NSString *_username; NSString *_password; } @property (nonatomic, retain, readonly) NSURL @property (nonatomic, copy) NSString @property (nonatomic, copy) NSString *baseUrl; *username; *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

Network Manager
Network Layer

Monday, May 28, 12

Network Manager
Network Layer

Request

Monday, May 28, 12

Network Manager
Network Layer

Request

Response

Monday, May 28, 12

Network Manager
Network Layer

Request

Response

Cache

Monday, May 28, 12

Network Manager
Network Layer

Request

Response

Cache

Client

Monday, May 28, 12

Network Manager
Network Layer
Network Manager
Request Response Cache Client

Monday, May 28, 12

Network Manager
Cosa deve fare

Creare ed eseguire le request tramite il client Gestire le code di request Gestire il suspend e il resume

Monday, May 28, 12

Network Manager
A cosa serve
A governare il network layer. Quando si vuole disaccopiare e gestire attivit complesse come le code, etc. Disaccoppia il view controller dallimplementazione di rete e di conseguenza aumenta la manutenibilit del codice.

Quando utilizzarlo Perch utilizzarlo

Monday, May 28, 12

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; @end

Monday, May 28, 12

Network Layer
Quando utilizzare un networking framework?

SEMPRE, quando possibile evitare di utilizzare Framework come ASIHTTPRequest o

direttamente NSURLConnection. Non ha senso. AFNetworking semplicano troppo la vita per non essere utilizzati. (Twitter e Facebook docet)

Monday, May 28, 12

Network Layer

Monday, May 28, 12

Network Layer
In conclusione


Monday, May 28, 12

HTTP Request & Response Tunneling SSH/VPN Ambienti (stage, produzione etc.) Cache (HTTP) Network Manager

Network Layer
In conclusione


Monday, May 28, 12

HTTP Request & Response Tunneling SSH/VPN Ambienti (stage, produzione etc.) Cache (HTTP) Network Manager

One more thing...

Monday, May 28, 12

One more thing...

Monday, May 28, 12

One more thing...


Oltre che leggere lapp deve poter anche inviare dei comandi al rover!

Monday, May 28, 12

Domain Model Layer


modelliamo il nostro business

Monday, May 28, 12

Domain Model Layer


Cosa deve fare

Gestire il dato (entit e relazioni) Gestire il comportamento Convertire il dato da una forma ad unaltra

Monday, May 28, 12

Model
Domain Model Layer

Monday, May 28, 12

Model
Domain Model Layer

Monday, May 28, 12

Model
Domain Model Layer
Model

Monday, May 28, 12

Model
Domain Model Layer
Model

Monday, May 28, 12

Model
Cosa deve fare

Rappresentare linformazione attraverso lausilio


di una struttura dati nativa o custom anche il comportamento

Possibilmente oltre al dato dovrebbe incorporare

Monday, May 28, 12

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

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; @end

Monday, May 28, 12

Mapper
Domain Model Layer

Monday, May 28, 12

Mapper
Domain Model Layer

Monday, May 28, 12

Mapper
Domain Model Layer
Model

Monday, May 28, 12

Mapper
Domain Model Layer
Model Mapper

Monday, May 28, 12

Mapper
Cosa deve fare

Denire le regole di traformazione da una


struttura dati ad unaltra (es. NSArray to NSObject) un sistema centralizzato

Gestire le regole e fornirle su richiesta attraverso

Monday, May 28, 12

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

Domain Model

Monday, May 28, 12

Domain Model
In conclusione

Entit e relazioni Mappatura

Monday, May 28, 12

Domain Model
In conclusione

Entit e relazioni Mappatura

Monday, May 28, 12

One more little thing

Monday, May 28, 12

One more little thing

Monday, May 28, 12

One more little thing


Lapplicazione deve funzionare anche OFFLINE

Monday, May 28, 12

Data Layer
persistiamo i nostri dati

Monday, May 28, 12

Data Layer
Cosa deve fare

Persistere le informazioni Recuperare le informazioni

Monday, May 28, 12

Store
Data Layer

Monday, May 28, 12

Store
Data Layer

Monday, May 28, 12

Store
Data Layer
Store

Monday, May 28, 12

Store
Data Layer
Store

Monday, May 28, 12

File system
File system Plist
NSCoding, NSKeyedArchiver, NSKeyedUnarchiver

NSDictionary, NSArray, NSFileManager

Monday, May 28, 12

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.html

Monday, May 28, 12

Manager
Data Layer

Monday, May 28, 12

Manager
Data Layer

Monday, May 28, 12

Manager
Data Layer
Store

Monday, May 28, 12

Manager
Data Layer
Store Manager

Monday, May 28, 12

Manager
Cosa deve fare

Fornire uninterfaccia di accesso ai dati persistiti Fornire strumenti di interrogazione

Monday, May 28, 12

Conclusioni
e quindi?

Monday, May 28, 12

Framework custom
Layer Network Layer Domain Model Data Layer Quando SEMPRE Leggere e scrivere Ofine

Monday, May 28, 12

Framework custom

Monday, May 28, 12

Framework custom
Vantaggi

Monday, May 28, 12

Framework custom
Vantaggi

Know-how

Monday, May 28, 12

Framework custom
Vantaggi

Know-how Modulare

Monday, May 28, 12

Framework custom
Vantaggi

Know-how Modulare Flessibile (Business)

Monday, May 28, 12

Framework custom
Vantaggi Svantaggi

Know-how Modulare Flessibile (Business)

Monday, May 28, 12

Framework custom
Vantaggi Svantaggi

Know-how Modulare Flessibile (Business)

Tempo (Costi)

Monday, May 28, 12

Framework custom
Vantaggi Svantaggi

Know-how Modulare Flessibile (Business)

Tempo (Costi) Skill

Monday, May 28, 12

Framework custom
Vantaggi Svantaggi

Know-how Modulare Flessibile (Business)

Tempo (Costi) Skill Declinato

Monday, May 28, 12

Soluzione C
API + Dominio di Business =

Monday, May 28, 12

RestKit
Che cosa ?
Restkit un framework Objective-C per iOS che ha lo scopo di facilitare l'interazione con i web-service.

Monday, May 28, 12

RestKit
Che cosa fa ?
HTTP PROTOCOL REST SOAP XML ENCODE PARSER CODE ACTIVE RECORD PATTERN MAPPING CACHE STRATEGY SQL

Monday, May 28, 12

Network Layer
Obiettivo
Ha la funzione di costruire e consegnare le richieste HTTP e processare le risposte che arrivano dal server remoto

Come raggiunge lobiettivo?


Attraverso tre attori principali

RKClient

RKRequest

RKResponse

Monday, May 28, 12

Network Layer
RKClient
Http headers - Type Authentication Base URL

RKClient

App
Monday, May 28, 12

Network Layer
RKClient
Http headers - Type Authentication Base URL

RKClient
Http headers - Type Authentication

Base URL

RKClient

App
Monday, May 28, 12

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

Esempio: invio richiesta e visualizzazione risposta


#import <UIKit/UIKit.h> #import <RestKit/RestKit.h> @interface MyViewController : UIViewController<RKRequestDelegate> {...

Network Layer

Una volta congurato 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

Network Layer
Siamo in grado di comunicare con un web service remoto, inviare richieste e processare risposte,

?
Web Service
Monday, May 28, 12

payload

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 RestKit

Monday, May 28, 12

Object Mapping
RKObjectManager RKObjectMapper RKObjectMapping

RKObjectMappingProvider

Quando carichiamo un risorsa remota tramite unistanza di RKObjectManager Quando un oggetto locale inviato al backend per essere processato

Le operazioni di mapping sono eseguite:

Monday, May 28, 12

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

App

Monday, May 28, 12

RKClient

Object Mapping
Esempio: caricare oggetti remoti in oggetti locali

Obiettivo: vogliamo recuperare una collection di question dal web service

Monday, May 28, 12

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, "identier" : 1 }, { "body" : "Che differenza c tra lead e lag?", "correctIdAnswer" : 2, "identier" : 2 } ] }

Monday, May 28, 12

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; @end

Monday, May 28, 12

Object Mapping
Un esempio: caricare oggetti remoti in oggetti locali Conguriamo RestKit
RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:@"https://api.pragmamark.org/quiz"]; Deniamo un mapping per la classe Question

RKObjectMapping* questionMapping = [RKObjectMapping mappingForClass: [Question class]]; [questionMapping mapKeyPath:@"identifier" toAttribute:@"identifier"]; [questionMapping mapKeyPath:@"body" toAttribute:@"body"]; [questionMapping mapKeyPath:@"correctIdAnswer" toAttribute:@"correctIdAnswer"]; [objectManager.mappingProvider setMapping:questionMapping forKeyPath:@"questions"]; Istruiamo il mapping provider ad usare questionMapping se incontra un @questions key path

Monday, May 28, 12

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

Object Mapping
Siamo in grado di comunicare con un web service remoto, inviare richieste e processare risposte Caricare rappresentazioni di oggetti remoti nella nostra App e mapparli in oggeti locali

Monday, May 28, 12

Object Mapping
JSON XML ...
Server payload
Inviare oggetti al server (Serialization)

Monday, May 28, 12

Object Mapping
Serialization? Unaltra operazione di mapping.

RKObjectSerializer
Mapping
attributi e relazioni

RKParser
[{ "body" : "Che cosa si intende per scope creep?", "correctIdAnswer" : 1, "identier" : 1 }, { "body" : "Che differenza c tra lead e lag?", "correctIdAnswer" : 2, "identier" : 2

Encoder

Request

Local Domain Objects

(NSMutableDictionary)

Intermediate Dictionary

Backend System

(XML, URL Form Encode...)

JSON

Monday, May 28, 12

Un esempio: inviare oggetti locale al server remoto Conguriamo RestKit


[[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions" forMethod:RKRequestMethodPOST];
Lo stesso mapping denito prima utilizzo per serializzare la classe

Object Mapping

[[RKObjectManager sharedManager] setSerializationMIMEType:RKMIMETypeJSON]; RKObjectMapping* questionSerializationMapping = [questionMapping inverseMapping]; [[RKObjectManager sharedManager].mappingProvider setSerializationMapping:questionSerializationMapping forClass: [Question class]];
Istruiamo il mapping provider ad usare questionSerializationMapping

Monday, May 28, 12

Un esempio: inviare oggetti locale al server remoto Creiamo loggetto


// 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];

Object Mapping

[[RKObjectManager sharedManager] postObject:question delegate:self];

Inviamo la richiesta...

...recuperiamo la risposta dal server


- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects { ! NSLog(@"Loaded statuses: %@", objects); }

RestKit sa che deve serializzare quando esegue un POST o un PUT

Monday, May 28, 12

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 est

Routing
ion s/7 89

RKObjectRouter

e /qu

54 6 / ns o i t s

Routing System

/qu e

sti on s/1 2

RKObjectRouter registra un mapping tra una classe


del dominio e un resource path per uno specico metodo HTTP.

Monday, May 28, 12

Ovvero, dove vivono gli oggetti? GET


[[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions/(idpk)" forMethod:RKRequestMethodGET];

Routing

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

Un esempio: inviare un oggetto al server


Deniamo default route che sar usato per tutti gli HTTP verbs (GET, POST, PUT e DELETE)

Routing

Inizializziamo il nostro route...

[[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions/(identifier)"];

[[RKObjectManager sharedManager].router routeClass:[Question class] toResourcePath:@"/questions" forMethod:RKRequestMethodPOST];


registriamo uno specico route per il verbo POST

Monday, May 28, 12

Un esempio: inviare oggetti locale al server remoto


RKObjectRouter quindi utilizzato per generare resource path quando utilizziamo getObject, deleteObject, postObject e putObject.

Routing

POST

// Nel setup dellApp abbiamo gi definito i mapping per questa classe Question* 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

Un esempio: inviare oggetti locale al server remoto


RKObjectRouter quindi utilizzato per generare resource path quando utilizziamo getObject, deleteObject, postObject e putObject.

Routing

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

Un esempio: inviare oggetti locale al server remoto


RKObjectRouter quindi utilizzato per generare resource path quando utilizziamo getObject, deleteObject, postObject e putObject.

Routing

DELETE
Question *question = [Question new]; question.identifier = [NSNumber numberWithInt: 3]; [[RKObjectManager sharedManager] deleteObject:question delegate:self];

/questions/3

Monday, May 28, 12

Ofine :| Core Data Integration


A questo punto, cosa siamo in grado di fare?
Interagire con il web service remoto Rappresentare le risorse remote in locale Modicare e inviare oggetti locali al backend

Monday, May 28, 12

Ofine :| Core Data Integration


Assenza di connettivit?

Monday, May 28, 12

Ofine :) Core Data Integration


Assenza di connettivit? Persistiamo i dati in locale con Core Data

Monday, May 28, 12

Ofine Core Data Integration


Vediamo come fare passo dopo passo.

RKManagedObjectStore
Setup RestKit

RKManagedObjectMapping

RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:@http://pragmamark.org]; objectManager.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:@Quiz.sqlite];


Indicare lo store

Monday, May 28, 12

Ofine Core Data Integration


Vediamo come fare passo dopo passo. Mapping
2
Utilizzare RKManagedObjectMapping

RKManagedObjectMapping* questionMapping = [RKManagedObjectMapping mappingForClass:[Question class]]; Questo permette al 3

Mapper di discriminare tra questionMapping.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:questionMapping forKeyPath:@"questions"];

Monday, May 28, 12

Ofine 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; @end

Monday, May 28, 12

Ofine Core Data Integration


@implementation Question @synthesize identifier; @synthesize body; @synthesize correctIdAnswer; @end @implementation Question @dynamic identifier; @dynamic body; @dynamic correctIdAnswer; @end
@dynamic vs @synthesize

Monday, May 28, 12

Ofine Core Data Integration


Data Model
6
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

Ofine Core Data Integration


Ora che succede?
{questions: [ { "body" : "Che cosa si intende per scope creep?", "correctIdAnswer" : 1, "identier" : 1 }, { "body" : "Che differenza c tra lead e lag?", "correctIdAnswer" : 2, "identier" : 2 }] }

Transient objects Local Domains Objects Persistent objects

mapping

(XML, Form URL Encode...)

JSON

Monday, May 28, 12

Ofine 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

Ofine 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 <xcoredata://62C52FE3-86E9-4FD0-9BA8-FAE16839477E/Question/p1> ; data: <fault>)", "<Question: 0x6b8f090> (entity: Question; id: 0x6e707a0 <xcoredata://62C52FE3-86E9-4FD0-9BA8-FAE16839477E/Question/p5> ; data: <fault>)", }

Monday, May 28, 12

Ofine 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 seeding


Monday, May 28, 12

RestKit Mapping & CoreData


Non sempre le risposte del web service sono come ce le aspettiamo(Anonimo)

In practice

Team Mobile

Team Server-side

Monday, May 28, 12

RestKit Mapping & CoreData Elaboriamo un p il nostro model

In practice

Aggiungiamo lentit Answer Question e Answer sono in relazione molti a molti Lidenticativo di Question in un oggetto nidicato Nellelenco delle question manca la key Path @questions

Monday, May 28, 12

RestKit Mapping & CoreData


{"_id": { "$identier": "4faf69fee4b0895a3ed9b1ff" }, { questions: [ "correctIdAnswer": 1, { "identier" : 1 "body": "Quale il signicato del termine "body" : "Che cosa si intende per scope creep?", lead?", "answers": [ "correctIdAnswer" : 1, { }, "identier": "3", { "identier" : 2 "body": "risposta B" "body" : "Che differenza c tra lead e lag?", }, "correctIdAnswer" : 2, { "identier": "1", }] "body": "risposta A" } } ] }, {...
Dove la key @questions ? {[ Come identichiamo il contenuto?

In practice

Monday, May 28, 12

RestKit Mapping & CoreData


@interface Question : NSManagedObject @property @property @property @property @end @interface Answer : NSManagedObject @property (nonatomic, copy) NSString* identifier; @property (nonatomic, copy) NSString* body; @property (nonatomic, retain) NSSet* questions; @end (nonatomic, (nonatomic, (nonatomic, (nonatomic, copy) NSString* copy) NSString* copy) NSNumber* retain) NSSet* identifier; body; correctIdAnswer; answers;

In practice

Monday, May 28, 12

//Mapping RKManagedObjectMapping* questionMapping = [RKManagedObjectMapping mappingForClass:[Question class]]; questionMapping.primaryKeyAttribute = @"identifier"; [questionMapping mapKeyPath:@"_id.$identifier" toAttribute:@"identifier"]; [questionMapping mapKeyPath:@"body" toAttribute:@"body"]; [questionMapping mapKeyPath:@"correctIdAnswer" toAttribute:@"correctIdAnswer"]; RKManagedObjectMapping* answerMapping = [RKManagedObjectMapping mappingForClass:[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];

RestKit Mapping & CoreData

In practice

Monday, May 28, 12

RestKit Mapping & CoreData

In practice

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

RestKit Mapping & CoreData

In practice

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

Le code Inviare richieste e processare risposte: i retroscena.


RKRequest RKResponse RKClient

Payload

Monday, May 28, 12

Le code Inviare richieste e processare risposte: i retroscena.


RKRequest RKResponse RKClient

Payload

RKRequestQueue

Monday, May 28, 12

Le code Inviare richieste e processare risposte: i retroscena.


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

Le code Inviare richieste e processare risposte: i retroscena.


Possiamo usarle per:

Raggruppare le chiamate per la paginazione, per la Effettuare il download di unentit complessa. Ad

ricerca, per il workow di acquisto, etc.. e utilizzare la sharedQueue per soddisfare la user action. 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, fotograe, tiles per le mappa ofine) attraverso percorsi esterni.

Monday, May 28, 12

Le code
Inviare richieste e processare risposte: i retroscena. Creare una coda...
RKRequestQueue *queue = [RKRequestQueue requestQueueWithName:nameQueue]; queue.concurrentRequestsLimit = 5;

Monday, May 28, 12

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

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

Conclusioni
e quindi?

Monday, May 28, 12

Buon senso

Monday, May 28, 12