So senden Sie JSON-Daten in der HTTP-Anforderung mit NSURLRequest

80

Ich bin neu in Objective-C und fange seit kurzem an, große Anstrengungen in die Anfrage / Antwort zu investieren. Ich habe ein funktionierendes Beispiel, das eine URL (über http GET) aufrufen und den zurückgegebenen JSON analysieren kann.

Das Arbeitsbeispiel hierfür ist unten

- (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];
}

Meine erste Frage lautet: Wird sich dieser Ansatz vergrößern? Oder ist dies nicht asynchron (was bedeutet, dass ich den UI-Thread blockiere, während die App auf die Antwort wartet)?

Meine zweite Frage lautet: Wie kann ich den Anforderungsteil ändern, um einen POST anstelle von GET durchzuführen? Ist es einfach, die HttpMethod so zu ändern?

[request setHTTPMethod:@"POST"];

Und schließlich - wie füge ich diesem Beitrag eine Reihe von JSON-Daten als einfache Zeichenfolge hinzu (zum Beispiel)?

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

Danke im Voraus

Toran Billups
quelle

Antworten:

105

Folgendes mache ich (bitte beachten Sie, dass der JSON, der zu meinem Server geht, ein Wörterbuch mit einem Wert (ein anderes Wörterbuch) für key = question..ie {: question => {dictionary}} sein muss):

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

Die empfangenen Daten werden dann verarbeitet von:

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

Dies ist nicht 100% klar und erfordert ein erneutes Lesen, aber alles sollte hier sein, um Ihnen den Einstieg zu erleichtern. Und soweit ich das beurteilen kann, ist dies asynchron. Meine Benutzeroberfläche ist während dieser Anrufe nicht gesperrt. Hoffentlich hilft das.

Mike G.
quelle
Alles sieht gut aus, außer dieser Zeile [dict objectForKey: @ "user_question"], nil]; - dict ist in Ihrer Stichprobe nicht deklariert. Ist das nur ein einfaches Wörterbuch oder etwas Besonderes?
Toran Billups
1
Das tut mir leid. Ja, "dict" ist nur ein einfaches Wörterbuch, das ich aus den Dokumenten der iOS-Benutzer lade.
Mike G
19
Dies verwendet die NSDictionaryInstanzmethode JSONRepresentation. Ich könnte vorschlagen, dass ich die NSJSONSerializationKlassenmethode dataWithJSONObjectanstelle des json-Frameworks verwende .
Rob
Es ist effizienter, die NSUInteger über eine NSNumber wie in einen NSString zu konvertieren [[NSNumber numberWithUnsignedInt:requestData.length] stringValue].
RespektTheCode
1
@MikeG Es wurde ein langjähriger und bisher unbemerkter Fehler im Codebeispiel behoben. Entschuldigung, für die Bearbeitung Ihres Beitrags;)
CouchDeveloper
7

Ich hatte eine Weile damit zu kämpfen. Ausführen von PHP auf dem Server. Dieser Code sendet einen JSON und erhält die JSON-Antwort vom Server

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

     }
 }];
user3344717
quelle
1
content type = "application / x-www-form-urlencoded" hat es geschafft. Vielen Dank
SamChen
Gute Antwort. Ich habe "application / json" in meinem Fall verwendet
Gajendra K Chauhan
6

Ich würde vorschlagen, ASIHTTPRequest zu verwenden

ASIHTTPRequest ist ein benutzerfreundlicher Wrapper um die CFNetwork-API, der einige der langwierigeren Aspekte der Kommunikation mit Webservern erleichtert. Es ist in Objective-C geschrieben und funktioniert sowohl in Mac OS X- als auch in iPhone-Anwendungen.

Es eignet sich zum Ausführen grundlegender HTTP-Anforderungen und zur Interaktion mit REST-basierten Diensten (GET / POST / PUT / DELETE). Die enthaltene ASIFormDataRequest-Unterklasse erleichtert das Senden von POST-Daten und -Dateien mithilfe von Multipart- / Formulardaten.


Bitte beachten Sie, dass der ursprüngliche Autor dieses Projekt eingestellt hat. Gründe und Alternativen finden Sie im folgenden Beitrag: http://allseeing-i.com/%5Brequest_release%5D ;

Persönlich bin ich ein großer Fan von AFNetworking

vikingosegundo
quelle
Duh, ich habe nicht. Es tut uns leid.
Almo
3

Die meisten von Ihnen wissen das bereits, aber ich poste dies, nur für den Fall, dass einige von Ihnen immer noch mit JSON in iOS6 + zu kämpfen haben.

In iOS6 und höher haben wir die NSJSONSerialization-Klasse , die schnell ist und nicht davon abhängt, "externe" Bibliotheken einzuschließen .

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

Auf diese Weise kann iOS6 und höher JSON jetzt effizient analysieren. Die Verwendung von SBJson ist auch eine Implementierung vor ARC und bringt diese Probleme auch mit sich, wenn Sie in einer ARC-Umgebung arbeiten.

Ich hoffe das hilft!

tony.stack
quelle
2

Hier ist ein großartiger Artikel mit Restkit

Es wird erläutert, wie verschachtelte Daten in JSON serialisiert und an eine HTTP-POST-Anforderung angehängt werden.

Cevaris
quelle
2

Da meine Bearbeitung von Mike Gs Antwort zur Modernisierung des Codes 3 zu 2 als abgelehnt wurde

Diese Bearbeitung sollte den Autor des Beitrags ansprechen und macht als Bearbeitung keinen Sinn. Es sollte als Kommentar oder Antwort geschrieben worden sein

Ich reposte meine Bearbeitung hier als separate Antwort. Diese Bearbeitung entfernt die JSONRepresentationAbhängigkeit mit, NSJSONSerializationwie Robs Kommentar mit 15 positiven Stimmen nahe legt.

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

Die empfangenen Daten werden dann verarbeitet von:

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

Hier ist ein aktualisiertes Beispiel, das NSURLConnection + sendAsynchronousRequest verwendet: (10.7+, iOS 5+). Die "Post" -Anforderung bleibt dieselbe wie bei der akzeptierten Antwort und wird hier aus Gründen der Klarheit weggelassen:

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);
         }
     }
}];
auco
quelle
Die Frage war über POST
Ahmad
2
Nein, der erste Teil der Frage befasst sich mit Asynchronität, und hier gibt es keine Antwort, die dies beantwortet. Prost auf die Ablehnung.
Auco
0

Sie können diesen Code zum Senden einer JSON-Zeichenfolge ausprobieren

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];
Jayesh Mardiya
quelle