Verwendung von sendAsynchronousRequest: queue: finishHandler:


74

Zweiteilige Frage

Erster Teil: Ich versuche, eine ASynchrone Anforderung an meine Datenbank zu erstellen. Ich mache es derzeit synchron, aber ich möchte beide Möglichkeiten kennenlernen, um besser zu verstehen, was los ist.

Derzeit habe ich meinen synchronen Anruf so eingerichtet.

- (IBAction)setRequestString:(NSString *)string
{
    //Set database address
    NSMutableString *databaseURL = [[NSMutableString alloc] initWithString:@"http://127.0.0.1:8778/instacodeData/"]; // imac development

    //PHP file name is being set from the parent view
    [databaseURL appendString:string];

    //call ASIHTTP delegates (Used to connect to database)
    NSURL *url = [NSURL URLWithString:databaseURL];

    //SynchronousRequest to grab the data
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSError *error;
    NSURLResponse *response;

    NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    if (!result) {
        //Display error message here
        NSLog(@"Error");
    } else {

        //TODO: set up stuff that needs to work on the data here.
        NSString* newStr = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
        NSLog(@"%@", newStr);
    }
}

Ich denke, ich muss den Anruf ersetzen

NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

mit der ASynchronous-Version

sendAsynchronousRequest:queue:completionHandler:

Ich bin mir jedoch nicht sicher, was ich an die Warteschlange oder den CompletionHandler übergeben soll. Beispiele / Lösungen wären sehr willkommen.

Teil zwei: Ich habe über Multitasking gelesen und möchte es unterstützen, indem ich sicherstelle, dass meine Verbindungsanfragen vollständig sind, wenn ein Interrupt auftritt. Ich bin diesem Beispiel gefolgt

Darin wird erklärt, wie man mehr Zeit gewinnt, wenn ein Interrupt auftritt. Ich verstehe, was er tut. Aber nicht, wie man ihn auf diese Verbindung anwendet. Wenn Sie Beispiele / Tutorials haben, die mir helfen, herauszufinden, wie man sie anwendet, wäre das großartig!

Antworten:


113

Teil 1:

NSURL *url = [NSURL URLWithString:urlString];

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
    if ([data length] > 0 && error == nil)
        [delegate receivedData:data];
    else if ([data length] == 0 && error == nil)
        [delegate emptyReply];
    else if (error != nil && error.code == ERROR_CODE_TIMEOUT)
        [delegate timedOut];
    else if (error != nil)
        [delegate downloadError:error];
}];

Für die Delegatenaufrufe. Welchen Delegaten soll ich in meine Header-Datei aufnehmen?
C. Johns

Sie sollten es an self
mbh

2
Diese Methoden sind in Ihrer Klasse. Sie können diese Methoden nach Belieben umbenennen. Oder nicht haben. aber setzen Sie den Code in das if dann sonst selbst. oder Sie können so aufrufen [self receiveData: data];
mbh

12
Ich glaube, NSURLErrorTimedOutder akzeptierte Wert ist vorbei ERROR_CODE_TIMEOUT.
Joe Masilotti

2
Hinweis: sendAsynchronousRequest:urlRequest queue:queue completionHandler:wurde in iOS 9
Richard

38

Hier ist ein Beispiel:

NSString *urlAsString = @"http://www.cnn.com";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];


[NSURLConnection
         sendAsynchronousRequest:urlRequest
         queue:[[NSOperationQueue alloc] init]
         completionHandler:^(NSURLResponse *response,
                             NSData *data,
                             NSError *error) 
        {

         if ([data length] >0 && error == nil)
         {

                        // DO YOUR WORK HERE

         }
         else if ([data length] == 0 && error == nil)
         {
             NSLog(@"Nothing was downloaded.");
         }
         else if (error != nil){
             NSLog(@"Error = %@", error);
         }

     }];

1
Verlieren Sie nicht das NSOperationQueue-Objekt? Es sieht so aus als ob. Oder verwenden Sie ARC und haben es einfach nicht erwähnt?
Lukas Petr

3
Ich benutze ARC, habe es nur nicht erwähnt. Danke für die Frage!
Floh

Sollte die Zeile 'sendAsynchronousRequest: request' 'sendAsynchronousRequest: urlRequest' sein?
Mick

@Flea Bitte meine verwandte Frage hier. stackoverflow.com/questions/24857919/…
Tyler Pfaff

25

Versuchen Sie für den Warteschlangenparameter diese Magie:

[NSOperationQueue mainQueue]

Dies funktioniert hervorragend, wenn Sie die Benutzeroberfläche nach Abschluss der Anforderung aktualisieren, da die Hauptwarteschlange der Hauptthread ist. Es gibt Ihnen im Wesentlichen das vorherige Verhalten von NSURLConnection. Wenn Sie jedoch vorhaben, in eine Datei zu schreiben oder zu dekomprimieren, können Sie eine Hintergrundwarteschlange erstellen und dann asynchron zur Hauptwarteschlange für die UI-Updates zurücksenden.


1
@MaciejSwic nein, wie in der Dokumentation angegeben: "Warteschlange: Die Operationswarteschlange, an die der Handlerblock gesendet wird, wenn die Anforderung abgeschlossen ist oder fehlgeschlagen ist." Es ist also der Completion-Handler, der auf dem Hauptthread ausgeführt wird. Dies kann eine gute Sache sein oder auch nicht, je nachdem, was Sie dort tun möchten.
Algorithmus und Blues

Nun, wenn Sie die Benutzeroberfläche aktualisieren, ist es das, was Sie wollen. Und es macht keinen Sinn, die Komplikation des Ausführens des Delegaten in einem Hintergrundthread hinzuzufügen, wenn dies nicht erforderlich ist. Die Verwendung der Hauptwarteschlange führt zu demselben Verhalten wie die alte NSURLConnection, die in den meisten Fällen in Ordnung sein sollte.
Malhal

9

Ich habe auf ein ähnliches Problem arbeiten, habe ich geschrieben , diese Frage und bekam eine klare Antwort hier , ich hoffe , das hilft mit Teil 2.

Für Teil 1 sind die anderen hier genannten gut, aber Sie müssen einen weiteren Scheck hinzufügen (ich habe unten eine Antwort geändert). Es ist möglich, dass Ihre Anfrage einen 404-Fehler (Seite nicht gefunden) zurückgibt. In diesem Fall erhalten Sie keinen Fehler und die Daten sind> 0. Die 200 ist eine gute Antwort. Sie können auch den StatusCode für 404 oder was auch immer überprüfen .

     [NSURLConnection
     sendAsynchronousRequest:urlRequest
     queue:[[NSOperationQueue alloc] init]
     completionHandler:^(NSURLResponse *response,
                         NSData *data,
                         NSError *error) 
    {
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
     if ([data length] >0 && error == nil && [httpResponse statusCode] == 200)
     {

                    // DO YOUR WORK HERE

     }

4

Da sendAsynchronousRequest:urlRequest queue:queue completionHandler:wurde in iOS 9 veraltet, und es wird empfohlen, stattdessen NSURLSession's zu-dataTaskWithRequest:completionHandler: verwenden. Es ist seit iOS 7 und höher verfügbar .

Original:

 NSURL *URL = [NSURL URLWithString:@"http://example.com"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 [NSURLConnection sendAsynchronousRequest:request
                                    queue:[NSOperationQueue mainQueue]
                        completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
     // ...
 }];

Von NSURLSession:

 NSURL *URL = [NSURL URLWithString:@"http://example.com"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                         completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         // ...
     }];

 [task resume];

2

sendAsynchronousRequestwurde in Swift veraltet. Bewegen Sie sich zu dataTaskWithRequest, zum Glück wird es so ziemlich genauso verwendet.

if let url = NSURL(string:"http://your_url") {

    let request:NSURLRequest = NSURLRequest(URL: url)
    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: config)

    let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in

    });

    task.resume()
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.