L'NSURLConnection proporciona el mètode més flexible per descarregar els continguts d'una URL. Proporciona una interfície simple per crear i cancel·lar una connexió i suporta una col·lecció de mètodes delegats que proporcionen realimentació i control de molts aspectes de la connexió. Aquestes classes entren dins de cinc categories: la càrrega d'URLs, la gestió de la memòria cau, l'autenticació i les credencials, l'emmagatzematge de galetes i el suport de protocols.
D'acord amb la descàrrega de continguts d'una URL, una aplicació necessita proporcionar un objecte delegat que, com a mínim, implementa els següents mètodes delegats: connection:didReceiveResponse:, connection:didReceiveData:, connection:didFailWithError: i connectionDidFinishLoading:.
L'exemple del Llistat 1 inicialitza una connexió per una URL. Comença creant una instància NSURLRequest per la URL, especificant la política d'accés a la memòria cau i l'interval de temps d'espera per la connexió. Llavors crea una instància d'NSURLConnection utilitzant la petició i especificant el delegat. Si l'NSURLConnection no pot crear una connexió per la petició, initWithRequest:delegate: retorna nil. Si la connexió es produeix, una instància d'NSMutableData es creada per emmagatzemar les dades que es proporcionaran incrementalment al delegat.
Llistat 1: Creant una connexió utilitzant NSURLConnection
// crear la petició
NSURLRequest *laPetició=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com/"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// crear la connexió amb la petició
// i comença la càrrega de les dades
laConnexio=[[NSURLConnection alloc] initWithRequest:laPeticio delegate:self];
if (laConnexio) {
// Crea la NSMutableData que mantindrà
// les dades rebudes
dadesRebudes=[[NSMutableData data] retain];
} else {
// informa a l'usuari que no s'ha pogut descarregar.
}
La descàrrega comença immediatament al rebre el missatge initWithRequest:delegate:. Pot cancel·lar-se en qualsevol moment abans que el delegat rebi un missatge connectionDidFinishLoading: o connection:didFailWithError: enviant un missatge cancel.
connection:didReceiveResponse:. El mètode delegat pot examinar la resposta NSURLResponse proporcionada i determinar la longitud del contingut esperat de les dades, el tipus MIME, els fitxers suggerits i altres metadades proporcionades pel servidor.
És important que el delegat estigui preparat per rebre el missatge connection:didReceiveResponse: múltiples vegades en una connexió. Aquest missatge pot enviar-se degut als redireccionaments del servidor, o en caos estranys a documents MIME de múltiples parts. Cada cop que el delegat rep el missatge connection:didReceiveResponse:, hauria de resetejar l'indicador de procés i descartar totes les dades rebudes prèviament. L'exemple implementat en el Llistat 2 simplement reseteja la longitud de les dades rebudes a 0 cada cop que es cridada.
Llistat 2: Exemple d'implementació de connection:didReceiveResponse:
- (void)connection:(NSURLConnection *)connexio didReceiveResponse:(NSURLResponse *)resposta
{
// aquest mètode es cridat quan el servidor ha determinat que té
// prou informació per crear una NSURLResponse
// pot ser cridada múltiples vegades, per exemple en el cas d'un
// redireccionament, i cada cop resetarem les dades
[dadesRebudes setLength:0];
}
A mida que la connexió progressa el delegat envia missatges connection:didReceiveData: amb les dades que ha rebut. La implementació del delegat és el responsable per emmagatzemar els dades rebudes més noves. En l'exemple d'implementació en el Llistat 3, les noves dades són afegides a l'objecte NSMutableData creat en el Llistat 1.
Llistat 3: Exemple d'implementació de connection:didReceiveData:
- (void)connection:(NSURLConnection *)connexio didReceiveData:(NSData *)dades
{
// afegeix les noves dades a les dadesRebudes
[dadesRebudes appendData:dades];
}
També pots utilitzar el mètode connection:didReceiveData: per proporcionar una indicació del progress de la connexió a l'usuari.
Si es troba un error durant la descàrrega, el delegat rep un missatge connection:didFailWithError:. L'objecte NSError passat com a paràmetre especifica els detalls de l'error. També proporciona la URL de la petició que falla en el diccionari d'informació de l'usuari utilitzant la clau NSErrorFailingURLStringKey.
Després que el delegat rep un missatge connection:didFailWithError:, no rep cap altre missatge del delegat per aquesta connexió.
L'exemple del Llistat 4 allibera la connexió, així com qualsevol dada rebuda i els informes d'error.
Llistat 4: Exemple d'implementació de connectionDidFailWithError:
- (void)connection:(NSURLConnection *)connexio
didFailWithError:(NSError *)error
{
// allibera la connxió, i les dades de l'objecte
[connexio release];
[dadesRebudes release];
// informem a l'usuari
NSLog(@"Connexió fallida! Error - %@ %@",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}
Finalment, si la connexió té èxit en la descàrrega de la petició, el delegat rep el missatge connectionDidFinishLoading:. El delegat no rebrà més missatges de la connexió i l'objecte NSURLConnection serà alliberat.
L'exemple implementat en el Llistat 5 informa de la longitud de les dades rebudes i alliberen la connexió i les dades rebudes.
Llistat 5: Exemple d'implementació de connectionDidFinishLoading:
- (void)connectionDidFinishLoading:(NSURLConnection *)connexio
{
// per quelcom amb les dades
NSLog(@"Fet! Rebuts %d bytes de dades",[dadesRebudes length]);
// allibera la connexió, i l'objecte de dades
[connexio release];
[dadesRebudes release];
}
Això representa la implementació més simple d'un client utilitzant l'NSURLConnection. Mètodes delegats adicionals proporcionen l'habilitat de personalitzar el tractament dels redireccionament del servidor, les peticions d'autorització i l'encauament de la resposta.
No és infreqüent que un servidor redireccioni una URL a una altra. El delegat de l'NSURLConnection rebrà un missatge connection:willSendRequest:redirectResponse: quan això passi.
Si el delegat implementa aquest mètode pot examinar la nova NSURLRequest i la NSURLResponse que ha produït la redirecció i permetre la petició NSURLRequest s'utilitzi per la connexió, crear una nova NSURLRequest per la connexió, refusar la redirecció i agafar el retorn de la redirecció amb les dades rebudes des de la NSURLResponse que ha produït la redirecció, o cancel·lar completament la descàrrega.
Per permetre la redirecció, el delegat hauria de retornar la NSURLRequest proporcionada. El delegat també podria crear un nou NSURLRequest, apuntant a la nova URL, i retornant-lo.
Si el delegat desitja refusar la redirecció, però rep alguna dada de la connexió, el mètode hauria de retornar nil.
Finalment, el delegat pot cancel·lar la redirecció i la connexió, enviant un missatge cancel a la connection.
El delegat també rebrà aquest missatge si la sub-classe de NSURLProtocol que tracta la petició que ha canviat la petició NSURLRequest per estandaritzar aquest format, per exemple, canviant una petició de "http://www.apple.com" < "http://www.apple.com/". Aquest és requerit doncs la versió estandaritzada o canònica de la petició s'utilitza per la gestió de la memòria cau. En aquesta cas especial, la resposta passada al delegat és nil i el delegat hauria simplement retornar la NSURLRequest proporcionada.
L'exemple d'implementació del Llistat 6 permet canvis canònics i denega totes les redireccions del servidor.
Llistat 6: Exemple d'implementació de connection:willSendRequest:redirectResponse:
-(NSURLRequest *)connection:(NSURLConnection *)connexio
willSendRequest:(NSURLRequest *)peticio
redirectResponse:(NSURLResponse *)respostaRedireccio
{
NSURLRequest *novaPeticio=peticio;
if (respostaRedireccio) {
novaPeticio =nil;
}
return novaPeticio;
}
Si el delegat no implementa el connection:willSendRequest:redirectResponse:, tots els canvis canònics i redireccions del servidor es permetran.
Si una petició requereix autenticació i no hi ha disponibles credencials vàlides, qualsevol part de la URL requerida o en la NSURLCredentialStorage compartida, els delegats de NSURLConnection rep un missatge connection:didReceiveAuthenticationChallenge:. Per que la connexió continuï, el delegat ha de proporcionar les credencials per intentar utilitzar com a autenticació, intentar continuar sense credencials, o cancel·lar la petició d'autenticació.
La instància NSURLAuthenticationChallenge passada al delegat conté informació sobre que ha activar el desafiament d'autenticació, el nombre d'intents que s'han realitzat, qualsevol credencial provada, la NSURLProtocolSpace que requereix les credencials, i l'enviador del desafiament.
Sovint el delegat demana a l'usuari que entri un nom d'usuari i paraula de pas vàlids. Si el desafiament d'autenticació ha intentat autenticar i ha fallat, les credencials provades seran retornades enviant challenge a un missatge proposedCredential. El delegat llavors pot utilitzar aquestes credencials per publicar un diàleg que el presenta a l'usuari.
Invocant previousFailureCount en el paràmetre challenge retorna el nombre d'intents d'autenticació. El delegat pot proporcionar aquesta informació a l'usuari final, determinar si les credencials donades anteriorment han fallat, o el limitar el nombre màxim d'intents d'autenticació.
A l'intentar autenticar, l'aplicació hauria de crear un objecte NSURLCredential amb el nom de l'usuari, la paraula de pas i el tipus de persistència a utilitzar per les credencials, i llavors enviar a l'[challenge sender] un missatge useCredential:forAuthenticatioinChallenge:.
Si el delegat escull no proporcionar una credencial per el desafiament d'autenticació, podrà intentar continuar sense aquest enviant al [challenge sender] un missatge continueWithoutCredentialsForAuthenticationChallenge:. Depenent de la implementació del protocol, aquest pot retornar un contingut d'una URL alternativa que no requereix autenticació o provocar que la connexió falli, rebent un missatge connectionDidFailWithError:.
El delegat també pot escollir cancel·lar el desafiament d'autenticació enviant un missatge cancelAuthenticationChallenge: al [challenge sender]. El delegat rep un missatge connection: didCancelAuthenticationChallenge: proporcionant-li l'oportunitat per dona realimentació a l'usuari.
L'exemple del Llistat 7 intenta autenticar el desafiament creant una instància d'NSURLCredential utilitzant un nom d'usuari i una paraula de pas proporcionada per les preferències de l'aplicació. Si l'autenticació ha fallat anteriorment, aquest cancel·la el desafiament d'autenticació i informa a l'usuari.
Llistat 7: Exemple del mètode delegat connection: didReceiveAuthenticationChallenge:
-(void)connection:(NSURLConnection *)conexio
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)desafiament
{
if ([desafiament previousFailureCount] == 0) {
NSURLCredential *novaCredencial;
novaCredencial =[NSURLCredential credentialWithUser:[self preferencesName]
password:[self preferencesPassword]
persistence:NSURLCredentialPersistenceNone];
[[desafiament sender] useCredential: novaCredencial
forAuthenticationChallenge: desafiament];
} else {
[[desafiament sender] cancelAuthenticationChallenge: desafiament];
// informa a l'usuari que el nom d'usuari i la paraula de pas
// de les preferències són incorrectes
[self showPreferencesCredentialsAreIncorrectPanel:self];
}
}
Si el delegat no implementa el connection:didReceiveAuthenticationChallenge: i la petició requereix autenticació, les credencials vàlides hauran d'estar disponibles pel NSURLCredentialStorage o han de proporcionar-se com a part de la URL demanada. Si les credencials no estan disponibles o fallen per autenticar, un missatge continueWithoutCredentialForAuthenticationChallenge: s'envia en la implementació de base.
Per defecte les dades per una connexió és encauada d'acord al suport proporcionat per la sub-classe NSURLProtocol que tracta la petició. Un delegat de NSURLConnection podrà refinar aquest comportament implementant connection:willCacheResponse:.
Aquest mètode delegat pot examinar l'objecte NSCachedURLResponse proporcionat i canviar com la resposta es encauada, potser restringint el seu emmagatzemament només a la memòria o prevenint-lo de tornar a ser encauada conjuntament. També és possible insertar objecte en un diccionari d'informació d'usuari de l'NSCachedURLResponse, provocant que sigui emmagatzemada en la memòria cau com part de la resposta.
Nota: El delegat rep missatges connection:willCacheResponse: només per protocols que permetin l'encauament.
|
L'exemple del Llistat 8 prevé els encauaments de les respostes https. També afegeix la data actual al diccionari d'informació d'usuari per respostes que s'han encauat.
Llistat 8: Exemple d'implementació de connection:withCacheResponse:
-(NSCachedURLResponse *)connection:(NSURLConnection *)conexio
willCacheResponse:(NSCachedURLResponse *)respostaCauada
{
NSCachedURLResponse *novaRespostaCauada= respostaCauada;
if ([[[[respostaCauada response] URL] scheme] isEqual:@"https"]) {
novaRespostaCauada =nil;
} else {
NSDictionary *novaInfoUsuari;
novaInfoUsuari =[NSDictionary dictionaryWithObject:[NSCalendarDate date]
forKey:@"Data Cauada"];
novaRespostaCauada =[[[NSCachedURLResponse alloc]
initWithResponse:[respostaCauada response]
data:[respostaCauada data]
userInfo: novaInfoUsuari
storagePolicy:[respostaCauada storagePolicy]]
autorelease];
}
return novaRespostaCauada;
}