web-dev-qa-db-fra.com

Comment envoyer des données JSON dans la requête Http à l'aide de NSURLRequest

Je suis nouveau sur Objective-c et je commence à mettre beaucoup d'effort dans demande/réponse à partir de récente. J'ai un exemple de travail qui peut appeler une URL (via http GET) et analyser le JSON renvoyé.

L'exemple de travail de ceci est ci-dessous

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [responseData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [responseData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
  NSLog([NSString stringWithFormat:@"Connection failed: %@", [error description]]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [connection release];
  //do something with the json that comes back ... (the fun part)
}

- (void)viewDidLoad
{
  [self searchForStuff:@"iPhone"];
}

-(void)searchForStuff:(NSString *)text
{
  responseData = [[NSMutableData data] retain];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.whatever.com/json"]];
    [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

Ma première question est la suivante: cette approche sera-t-elle renforcée? Ou est-ce pas asynchrone (ce qui signifie que je bloque le fil de l'interface utilisateur pendant que l'application attend la réponse)

Ma deuxième question est la suivante: comment puis-je modifier la partie requête de cette opération pour faire un POST au lieu de GET? S'agit-il simplement de modifier le HttpMethod de cette manière?

[request setHTTPMethod:@"POST"];

Et enfin - comment puis-je ajouter un ensemble de données JSON à cette publication sous forme de chaîne simple (par exemple)

{
    "magic":{
               "real":true
            },
    "options":{
               "happy":true,
                "joy":true,
                "joy2":true
              },
    "key":"123"
}

Merci d'avance

78
Toran Billups

Voici ce que je fais (veuillez noter que le JSON envoyé sur mon serveur doit être un dictionnaire avec une valeur (un autre dictionnaire) pour key = question..i.e. {: Question => {dictionary}}):

NSArray *objects = [NSArray arrayWithObjects:[[NSUserDefaults standardUserDefaults]valueForKey:@"StoreNickName"],
  [[UIDevice currentDevice] uniqueIdentifier], [dict objectForKey:@"user_question"],     nil];
NSArray *keys = [NSArray arrayWithObjects:@"nick_name", @"UDID", @"user_question", nil];
NSDictionary *questionDict = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

NSDictionary *jsonDict = [NSDictionary dictionaryWithObject:questionDict forKey:@"question"];

NSString *jsonRequest = [jsonDict JSONRepresentation];

NSLog(@"jsonRequest is %@", jsonRequest);

NSURL *url = [NSURL URLWithString:@"https://xxxxxxx.com/questions"];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
             cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];


NSData *requestData = [jsonRequest dataUsingEncoding:NSUTF8StringEncoding];

[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody: requestData];

NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if (connection) {
 receivedData = [[NSMutableData data] retain];
}

ReceiveData est ensuite traité par:

NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [jsonString JSONValue];
NSDictionary *question = [jsonDict objectForKey:@"question"];

Ce n'est pas clair à 100% et il faudra un peu de relecture, mais tout devrait être là pour vous aider à démarrer. Et d'après ce que je peux dire, c'est asynchrone. Mon interface utilisateur n'est pas verrouillée pendant ces appels. J'espère que ça t'as aidé.

104
Mike G

J'ai eu du mal avec ça pendant un moment. En cours d'exécution PHP sur le serveur. Ce code publiera un JSON et obtiendra la réponse JSON du serveur.

NSURL *url = [NSURL URLWithString:@"http://example.co/index.php"];
NSMutableURLRequest *rq = [NSMutableURLRequest requestWithURL:url];
[rq setHTTPMethod:@"POST"];
NSString *post = [NSString stringWithFormat:@"command1=c1&command2=c2"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding];
[rq setHTTPBody:postData];
[rq setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[NSURLConnection sendAsynchronousRequest:rq queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
 {
     if ([data length] > 0 && error == nil){
         NSError *parseError = nil;
         NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
         NSLog(@"Server Response (we want to see a 200 return code) %@",response);
         NSLog(@"dictionary %@",dictionary);
     }
     else if ([data length] == 0 && error == nil){
         NSLog(@"no data returned");
         //no data, but tried
     }
     else if (error != nil)
     {
         NSLog(@"there was a download error");
         //couldn't download

     }
 }];
7
user3344717

Je suggère d'utiliser ASIHTTPRequest

ASIHTTPRequest est un encapsuleur facile à utiliser autour de l'API CFNetwork qui facilite certains des aspects les plus fastidieux de la communication avec les serveurs Web. Il est écrit en Objective-C et fonctionne dans les applications Mac OS X et iPhone.

Il est approprié d'effectuer des requêtes HTTP de base et d'interagir avec des services basés sur REST (GET/POST/PUT/DELETE). La sous-classe ASIFormDataRequest incluse facilite l'envoi de données POST et de fichiers à l'aide de multipart/form-data.


Veuillez noter que l'auteur original a abandonné ce projet. Voir le post suivant pour les raisons et les alternatives: http://allseeing-i.com/%5Brequest_release%5D ;

Personnellement, je suis un grand fan de AFNetworking

6
vikingosegundo

La plupart d’entre vous le savent déjà, mais je publie ce message. Certains d'entre vous ont encore du mal à utiliser JSON dans iOS6 +.

Dans iOS6 et les versions ultérieures, nous avons le NSJSONSerialization Class qui est rapide et ne dépend pas de l'inclusion de bibliothèques "extérieures".

NSDictionary *result = [NSJSONSerialization JSONObjectWithData:[resultStr dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; 

C'est ainsi qu'iOS6 et les versions ultérieures peuvent désormais analyser efficacement JSON. L'utilisation de SBJson est également une implémentation antérieure à ARC et apporte ces problèmes également si vous travaillez dans un environnement ARC.

J'espère que ça aide!

3
tony.stack

Depuis mon édition à la réponse de Mike G pour moderniser le code a été rejetée 3 à 2 comme

Cette modification était destinée à s’adresser à l’auteur du message et n’a aucun sens en tant que modification. Il aurait dû être écrit comme un commentaire ou une réponse

Je republie mon édition comme une réponse séparée ici. Cette modification supprime la dépendance JSONRepresentation avec NSJSONSerialization comme le suggère le commentaire de Rob avec 15 votes positifs.

    NSArray *objects = [NSArray arrayWithObjects:[[NSUserDefaults standardUserDefaults]valueForKey:@"StoreNickName"],
      [[UIDevice currentDevice] uniqueIdentifier], [dict objectForKey:@"user_question"],     nil];
    NSArray *keys = [NSArray arrayWithObjects:@"nick_name", @"UDID", @"user_question", nil];
    NSDictionary *questionDict = [NSDictionary dictionaryWithObjects:objects forKeys:keys];

    NSDictionary *jsonDict = [NSDictionary dictionaryWithObject:questionDict forKey:@"question"];

    NSLog(@"jsonRequest is %@", jsonRequest);

    NSURL *url = [NSURL URLWithString:@"https://xxxxxxx.com/questions"];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                 cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];


    NSData *requestData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:nil]; //TODO handle error

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-Length"];
    [request setHTTPBody: requestData];

    NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    if (connection) {
     receivedData = [[NSMutableData data] retain];
    }

ReceiveData est ensuite traité par:

NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSDictionary *question = [jsonDict objectForKey:@"question"];
2
Steve Moser

Voici un excellent article utilisant Restkit

Il explique comment sérialiser des données imbriquées dans JSON et les attacher à une requête HTTP POST.

2
cevaris

Voici un exemple mis à jour qui utilise NSURLConnection + sendAsynchronousRequest: (10.7+, iOS 5+), la requête "Post" reste identique à celle de la réponse acceptée et est omise ici pour des raisons de clarté:

NSURL *apiURL = [NSURL URLWithString:
    [NSString stringWithFormat:@"http://www.myserver.com/api/api.php?request=%@", @"someRequest"]];
NSURLRequest *request = [NSURLRequest requestWithURL:apiURL]; // this is using GET, for POST examples see the other answers here on this page
[NSURLConnection sendAsynchronousRequest:request
                                   queue:[NSOperationQueue mainQueue]
                       completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
     if(data.length) {
         NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
         if(responseString && responseString.length) {
             NSLog(@"%@", responseString);
         }
     }
}];
0
auco

Vous pouvez essayer ce code pour envoyer une chaîne json

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:ARRAY_CONTAIN_JSON_STRING options:NSJSONWritin*emphasized text*gPrettyPrinted error:NULL];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *WS_test = [NSString stringWithFormat:@"www.test.com?xyz.php&param=%@",jsonString];
0
jayesh mardiya