Este artigo trata sobre requisições http a servidores web externos. Essa técnica é útil para quem quer conectar-se com API’s externas, como a do Facebook ou a do Twitter. Vou abordar os seguintes assuntos: JSON, Categories, NSURL, NSData.

Programadores de iOS 4 devem estar acostumados com uma biblioteca JSON externa para desenvolvimento. Felizmente a Apple adicionou uma biblioteca nativa de JSON ao iOS 5. Mas vamos lá, mãos à obra.

Conexão com um servidor externo

Em Objective-C é muito fácil se conectar a um servidor externo via http, basta seguir os passos abaixo:

1 - Criar um objeto NSURL

NSURL é uma classe que guarda URL’s (Uniform Resource Locator) tanto para servidores externos quanto para diretórios no filesystem do iPhone. Nesse caso, vamos usar o método urlWithString, que gera um objeto NSURL a partir de uma string com o link.

NSURL* url = [NSURL urlWithString: @”http://seu-web-site.com/api/algo”];
Se você quiser ver como ficou a requisição, pode dar uma série de NSLogs:
NSLog(@"Scheme: %@", [url scheme]); 
NSLog(@"Host: %@", [url host]); 
NSLog(@"Port: %@", [url port]);     
NSLog(@"Path: %@", [url path]);     
NSLog(@"Relative path: %@", [url relativePath]);
NSLog(@"Path components as array: %@", [url pathComponents]);        
NSLog(@"Parameter string: %@", [url parameterString]);   
NSLog(@"Query: %@", [url query]);       
NSLog(@"Fragment: %@", [url fragment]);

2 - Criar um NSData

NSData é um objeto do Foundation framework e representa uma série de bytes. O NSData não faz ideia se aquela sequencia de bytes forma um número, uma string ou qualquer outra coisa.

NSData possui um método de classe chamado: dataWithContentsOfUrl que faz a requisição http, pega e guarda a resposta em um objeto. Esse método leva como argumento a URL que criamos anteriormente, que é aonde ele vai conectar-se.

NSData *data = [NSData dataWithContentOfUrl:url];
Pronto, dentro desse NSData já temos uma resposta em JSON, agora só falta transformar o conteúdo da resposta em algo legível para nós.

A biblioteca JSON no iOS 5

O nome da classe que faz a leitura do JSON é NSJSONSerialization. Vamos ver como essa classe funciona. Para fazer isso vamos usar um método chamado JSONObjectWithData:options:error: que transforma um objeto NSData em um NSDictionary ou um NSArray. Nesse tutorial vamos usar um NSDictionary.

NSDictionary

NSDictionary é uma estrutura de dados que armazena valores a partir de uma KEY, podemos comparar com o std::map de C++, ou talvez até com um $array[“key”] do PHP. Para acessar seus dados, usamos o método objectForKey.

1 - Transformação de NSData para NSDictionary

NSError* error;
NSDictionary* json = 
[NSJSONSerialization JSONObjectWithData: data options: 
kNilOptions error: &error];
Como podem ver no código acima, estamos transformando um NSData em um NSDictionary. O método JSONObjectWithData leva 3 argumentos: o objeto NSData que ele vai transformar, options que são as opções de transformação e uma variável para armazenar algum erro, caso aconteça. A constante kNilOptions é uma constante para SEM OPÇÕES.

2 - Leitura do Dictionary

Cada chave no NSDictionary representa um objeto do JSON, e se esse objeto contém mais objetos dentro dele, um novo dictionary é criado, veja o exemplo abaixo:

{
	"webcam": { // objeto “webcam” com 3 objetos dentro dele
		"webcamid": "1234",
		"title": "Foo",
		"owner": "Bar"
	}
}
NSDictionary *dict = [json objectForKey:@”webcam”]; 
// O objeto webcam é um dictionary
NSString* title= [dict objectForKey: @”title”]; 
// objeto title dentro do objeto webcam
NSLog(title); 
// Vai logar Foo
Como podem perceber, dentro do objeto “webcam” há outros objetos, portanto ele retorna um dictionary. A partir daí, objetos normais são strings ou números.

Criando uma categoria para facilitar o desenvolvimento

Vamos fazer uma CATEGORIA na classe NSDictionary, uma categoria é um artifício em que você pode adicionar funções a uma classe sem herdá-la.

1 - Criar o arquivo da categoria

No XCode vá a File -> New -> New File e no menu Cocoa Touch escolha: Objective-C category.



Agora haverá dois formulários assim:

Category:
Category on:
Isso é o nome da categoria e a classe em que quer colocá-la, no nosso caso chamaremos de JSONCategory e a colocaremos na classe NSDictionary.



Será criado um arquivo chamado NomeDaClasse + NomeDaCategoria e você vai ter algo parecido com isso:

NSDictionary+JSONCategory.h
@interface NSDictionary (JSONCategory)

@end
NSDictionary+JSONCategory.m
@implementation NSDictionary (JSONCategory)

@end
Vamos adicionar as seguintes funções ao NSDictionary+JSONCategory.h:
+(NSDictionary*)dictionaryWithContentsOfJSONURLString: (NSString*)urlAddress;

-(NSData*) toJSON;
O método dictionaryWithContentsOfJSONURLString recebe um argumento com o endereço do URL da API em que você quer conectar-se.

O método toJSON transforma o dicionário em NSData com um JSON.

Agora vamos implementar essas funções:
+(NSDictionary*)dictionaryWithContentsOfJSONURLString:
  (NSString*)urlAddress
{
    NSData* data = [NSData dataWithContentsOfURL:
      [NSURL URLWithString: urlAddress] ]; // Pega a data e a resposta
    __autoreleasing NSError* error = nil; //Variavel que guardara o erro
    id result = [NSJSONSerialization JSONObjectWithData:data 
      options:kNilOptions error:&error]; // Faz le o resultado do JSON
    if (error != nil) return nil;
    return result; // Retorna o dictionary 
}
 
-(NSData*)toJSON
{
    NSError* error = nil;
    id result = [NSJSONSerialization dataWithJSONObject:self 
      options:kNilOptions error:&error]; 
       // Transforma um dictionary em um NSData com JSON
    if (error != nil) return nil;
    return result;    
}
A única coisa nova apresentada nessas implementações é o método:
dataWithJSONObject que transforma o dictionary em um objeto NSData contendo os bytes do json criado a partir do dictionary.

Exemplo de como usar:

NSDictionary dict = [NSDictionary dictionaryWithObjectsAndKeys: 
@”hey”,@”hey2”,nil];
NSData* data = [dict toJSON]; 
// Pronto, você tem uma NSData com JSON pronta para enviar a algum servidor.
Bem, o útlimo método que eu queria comentar é o: isValidJSONObject: que verifica se algum objeto pode ser transformado em JSON, por exemplo:
BOOL ableToBeJson = [JSONSerialization isValidJsonObject: object]; 
// retorna YES ou NO dependendo se aquele objeto está apto 
//para virar um JSON ou não

Conclusão


Este artigo foi criado por Henrique Dubugras.

Contato: dubugras@ingresse.com