Az Objective-C programozási nyelv

NSURLConnection

NSURLConnection használata

Az NSURLConnection a leghatékonyabb módszer ahhoz, hogy tartalmakat lekérjünk az URL-ről. Az osztály egy egyszerű interfésszel rendelkezik kapcsolatok létrehozásához, megszüntetéséhez és támogatja a delegate collection metódusokat, melyek visszajelzéseket adnak, és amelyek bizonyos szempontokból figyelik a kapcsolatokat. Ezek az osztályok az alábbi kategóriákba sorolhatóak: URL betöltése, sütik menedzselése, autentikáció és bizonyítvány, sütik tárolása és protokoll támogatása.

Kapcsolat létrehozása

Az NSURLConnection osztály három kapcsolatot támogat az URL tartalom letöltéséhez, mégpedig: szinkronhívásokat, aszinkron hívásokat kiegészítő blokkokkal, és saját delegate objektumokat aszinkron híváskor.

URL tartalmának letöltése szinkron hívás segítségével

Az URL tartalmának letöltése szinkron hívás segítségével úgy működik, hogy a végrehajtás kizárólag háttér szálban fut. Ezt a következő módon kell meghívni: sendSynchronousRequest:returningResponse:error: egy HTTP kérés végrehajtásához. Ez a hívás akkor tér vissza, amikor a kérés befejeződik vagy egy hiba lép fel.

URL tartalmának letöltése kiegészítő blokkok segítségével

Ezt akkor használjuk, ha nem szeretnék kilistázni a kérésünk állapotát, de végre szeretnénk hajtani néhány műveletet, amikor a kérésünk teljesen megérkezett. Ekkor az alábbi parancsot hívhatjuk meg: sendAsynchronousRequest:queue:completionHandler:, átadunk egy blokkot, ami az eredményt kezeli.

URL tartalmának letöltése delegate objektum segítségével

Ha ezt szeretnénk használni, ekkor elsősorban a delegate osztályunknak az alábbi interfészeket kell implementálnia: connection:didReceiveResponse:, connection:didReceiveData:, connection:didFailWithError: és connectionDidFinishLoading:. A támogatott delegate metódusok a NSURLConnectionDelegate, NSURLConnectionDownloadDelegate, és NSURLConnectionDataDelegate protokollokban vannak definiálva.

Az alábbi példa inicializál egy kapcsolatot az URL-hez. Ez a kódrészlet egy NSURLRequest példánnyal kezdődik az URL számára, beleértve a sütik hozzáférési irányelvét és a kapcsolat szétbontási intervallumának a hosszát. Ekkor hozz létre egy NSURLConnection példányt, amivel megnevezi a kérést és a delegate metódust. Ha az NSURLConnection nem tudja létrehozni a kapcsolatot a kéréshez, akkor az initWithRequest:delegate: nil-el tér vissza. Ez a kódrészlet egy NSMutableData példányt is létre hoz, amiben az adatokat tárolja, és amely lépésenként hozzáadja a delegate objektumhoz.

// létrehozza a kérést. NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://inf.elte.hu/"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; // létrehozza az NSMutableData-t a megérkezet adatok tárolásához. // receivedData egy példányváltozó, ami máshol van deklarálva. receivedData = [NSMutableData dataWithCapacity: 0]; // létrehozza a kapcsolatot a kéréssel // és elkezdi tölteni az adatot NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; if (!theConnection) { // feloldjuk a receivedData objektumot receivedData = nil; // szól a felhasználónak, hogy nem sikerült a kapcsolat }

Az adatok átvitele azonnal elkezdődik, ahogy az initWithRequest:delegate: üzenetet megkapja. Bármikor le lehet állítani még mielőtt a delegate megérkezik a connectionDidFinishLoading: vagy connection:didFailWithError: egy cancel üzenet küldésével a kapcsolatnak.

Amikor a szerver elegendő adatot kiszolgált ahhoz, hogy létrehozzon egy NSURLResponse objektumot, a delegate metódus megkapja a connection:didReceiveResponse: üzenetet. A delegate metódus meg tudja vizsgálni a kiszolgált NSURLResponse objektumot és meg tudja határozni a pontos hosszát az adat tartalmának, mint pl. a MIME típusát, javasolt fájlnevét és más metaadatokat a szerver kiszolgálásáról.

Fel kell készülnünk arra is, hogy a connection:didReceiveResponse: függvényünk többször ki lehet szolgálva egy sima kapcsolat során. Ez akkor szokott előfordulni, ha a kiszolgált elemünk többrétegű MIME encoding-ot tartalmaz. Minden egyes delegate megkapja connection:didReceiveResponse: üzenetet. Ennek minden lefutása után arra van szükségünk, hogy lenullázzuk az előző értéket.

Az alábbi példában lenullázzuk minden hívás után a fent említett függvényt.

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { // ez a függvény akkor hívódik meg mikor elhatározta azt, hogy // elegendő adattal rendelkezik, ahhoz hogy létrehozza az NSURLResponse objektumot // többször is meghívódhat, például mikor az átirányítás történik, így mindig lenullázzuk az adatot // receivedData példányobjektum, kívülről van deklarálva [receivedData setLength:0]; }

A delegate hívás folyamatosan elküldi a connection:didReceiveData metódusnak az üzeneteket, ahogy az adat megérkezik. A delegate implementáció arra képes, hogy elmentse az újonnan érkezett adatot. Az alábbi példában az új adat hozzá lett adva az NSMutableData objektumhoz.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // hozzáadjuk az új adatot a receivedData objektumhoz // receivedData példányobjektum, kívülről van deklarálva [receivedData appendData:data]; }

Ha esetleg hiba történne az adatcsere során, a delegate metódus kap egy connection:didFailWithError: üzenetet. Ezt az üzenetet az NSError objektumnak átadva, meghatározza a részleteket a hibáról. Az URL-t is tartalmazza, ahonnan a kérés érkezett, mely elhasalt a felhasználónak az NSURLErrorFailingURLStringErrorKey objektumában. A delegate után kap egy connection:didFailWithError: üzenetet, ekkor már nem kap több delegate üzenetet az adott kapcsolattól.

Az alábbi kódrészletben megmutatjuk, hogyan szabadítjuk fel a kapcsolatot, az összes kapott adatot, valamint kiírjuk a hibaüzeneteket.

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { // felszabadítjuk a connection-t és a data objektumot úgy, hogy nil-re állítjuk az értéküket. // Az objektumokat kívülről deklaráltuk theConnection = nil; receivedData = nil; // kiírjuk konzolba a hibaüzeneteket NSLog(@"Connection failed! Error - %@ %@", [error localizedDescription], [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]); }

Végül, ha a kapcsolati kérésünk sikeresen megérkezett, a delegate megkapja a connectionDidFinishLoading: üzenetet. Ekkor már semmi más adatot nem kap a kapcsolattól, és az alkalmazás felszabadíthatja az NSURLConnection objektumot.

Az alábbi példa megmutatja a sikeres URL lekérés után megérkezett adatok hosszát és felszabadítja a connection objektumot, valamit a receivedData objektumot.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { // csináljuk valamit az adattal…, a receivedData és a theConnection kívülről van deklarálva NSLog(@"Succeeded! Received %d bytes of data",[receivedData length]); // felszabadítjuk a connection-t és a data objektumot úgy, hogy nil-re állítjuk őket. theConnection = nil; receivedData = nil; }

JSON connection lekérése és feldolgozása

A JSON (JavaScript Object Notation) egy kis méretű, szöveg alapú szabvány ember által olvasható adatcserére. A JavaScript szkriptnyelvből alakult ki egyszerű adatstruktúrák és asszociatív tömbök reprezentálására (a JSON-ban objektum a nevük).

Egy egyszerű példa JSON formátumra a következő:

[ { "Id" : 1, "Name" : "IK" }, { "Id" : 2, "Name" : "TTK" }, { "Id" : 3, "Name" : "BTK" } ]

Ha a fenti kérést szeretnék feldolgozni, akkor a fenti kódot kicsit módosítanunk kell. Az URL helyére beleírjuk a célállomást, majd a connectionDidFinishLoading: metódust a következő kódrészlettel kell kiegészítenünk. A kiegészítés ki van emelve.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.responseData appendData:data]; response = [[NSString alloc] initWithData:self.responseData encoding:NSISOLatin1StringEncoding]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"Succeeded! Recived %lu bytes of data", (unsigned long)[self.responseData length]); // NSError példány NSError *error; // Asszociatív json példány létrehozása és inicializálása NSDictionary *json = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:&error]; // ha hiba történt, kiíratjuk, hogy pontosan mi okozta a hibát if (error) { NSLog(@"ERROR %@", [error localizedDescription]); // ha nem volt hiba, bejárjuk a tömböt és az adatokat hozzáadjuk az options tömbhöz, ami egy // NSMutableArray példánya, ami kívülről van deklarálva, majd kiíratjuk a konzol ablakba az // eredményt } else { for (id key in json) { [options addObject:[key objectForKey:@"Name"]]; } NSLog(@"Name: %@", options); } }

Az NSJSONSerialization osztály annyit csinál, hogy a JSON objektumokat Foundation objektumokra konvertálja, illetve a Foundation objektumokat JSON objektumokká konvertál.