Cum se returnează NSData de la gestionarul de finalizare NSURLSessionDataTask (Programare, Ios, Obiectiv C, Ios7, Nsurlsession)

Carol Smith a intrebat.

Încerc să fac o clasă simplă pe care să o pot folosi pentru a apela un serviciu web post.

Totul funcționează perfect, cu excepția faptului că nu reușesc să returnez NSData.

Acesta este codul meu:

+ (NSData *)postCall:(NSDictionary *)parameters fromURL:(NSString *)url{
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSMutableArray *pairs = [[NSMutableArray alloc]init];
    for(NSString *key in parameters){
        [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, parameters[key]]];
    }
    NSString *requestParameters = [pairs componentsJoinedByString:@"$"];
    NSURL *nsurl = [NSURL URLWithString:url];
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:nsurl];
    [urlRequest setHTTPMethod:@"POST"];
    [urlRequest setHTTPBody:[requestParameters dataUsingEncoding:NSUTF8StringEncoding]];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        //return data;
    }];
    [dataTask resume];

    return nil;
}

Vă rugăm să observați că am //return data dar îmi dă următoarea eroare

 Incompatible block pointer types sending 'NSData *(^)(NSData *__strong, NSURLResponse *__strong, NSError *__strong)' to parameter of type 'void (^)(NSData *__strong, NSURLResponse *__strong, NSError *__strong)'

Întrebarea mea este:

  1. Este drumul meu bun sau îmi va cauza probleme în viitor? Nu am imagine de descărcat și nu am nimic de încărcat, trebuie doar să trimit date simple de tip șir de caractere și să primesc date simple de tip șir de caractere. Sau va fi mai bine să dar acel cod în fiecare funcție în mod independent?

  2. Cum pot să returnez datele, vă rog?

Comentarii

  • BTW, concatenarea parametrilor de cerere cu $. Este corect? În general, se utilizează &. De asemenea, în general, în general, scăpați la sută din parameters[key] cu CFURLCreateStringByAddingPercentEscapes (nu stringByAddingPercentEscapesUsingEncoding). See stackoverflow.com/a/23635327/1271826. –  > Por Rob.
2 răspunsuri
Rob

Nu puteți returna pur și simplu datele (deoarece NSURLSessionDataTask se execută în mod asincron). Probabil că doriți să utilizați propriul model de bloc de finalizare, similar cu modelul completionHandler din dataTaskWithRequest metodei.

Așadar, veți adăuga propriul parametru de bloc la metoda dvs., pe care îl veți invoca din interiorul secvenței dataTaskWithRequest din cadrul metodei completionHandler:

+ (NSURLSessionDataTask *)postCall:(NSDictionary *)parameters fromURL:(NSString *)url completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler {

    // create your request here ...

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (completionHandler)
            completionHandler(data, response, error);
    }];

    [dataTask resume];

    return dataTask;
}

Sau, deoarece acest dataTaskWithRequest se execută pe un fir de execuție în fundal, uneori este util să vă asigurați că trimiteți gestionarul de finalizare înapoi la coada principală, de exemplu.

NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (completionHandler)
        dispatch_async(dispatch_get_main_queue(), ^{
            completionHandler(data, response, error);
        });
}];

Notă, ca o paranteză, cred că este bine să se returneze NSURLSessionDataTask ca mai sus, astfel încât (a) apelantul să se poată asigura că sarcina de date a fost creată cu succes; și (b) să aveți NSURLSessionTask referință pe care o puteți utiliza pentru a anula sarcina în cazul în care, la o dată viitoare, doriți să puteți anula cererea din anumite motive (de exemplu, utilizatorul închide controlerul de vizualizare din care a fost emisă cererea).

În orice caz, ați putea invoca acest lucru cu:

NSURLSessionTask *task = [MyClass postCall:parameters fromURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    // put whatever code you want to perform when the asynchronous data task completes
}];

if (!task) {
    // handle failure to create task any way you want
}

Cereți:

Este bună metoda mea sau îmi va cauza probleme în viitor? Nu am [o] imagine de descărcat și nu am nimic de încărcat, trebuie doar să trimit [niște] date simple de tip șir de caractere și să primesc date [simple] de tip șir de caractere. Sau va fi mai bine să dar acel cod în fiecare funcție în mod independent?

Dacă primiți date simple de tip șir de caractere înapoi, v-aș sugera să compuneți răspunsul în format JSON, iar apoi să aveți blocul de completare în postCall use NSJSONSerialization pentru a extrage răspunsul. Folosind JSON este mai ușor pentru aplicație să diferențieze între un răspuns de succes și o varietate de probleme legate de server care ar putea, de asemenea, să returneze răspunsuri de tip șir de caractere.

Așadar, să spunem că ați modificat codul serverului pentru a returna un răspuns de genul acesta:

{"response":"some text"}

Atunci ați putea modifica postCall pentru a analiza acel răspuns astfel:

+ (NSURLSessionDataTask *)postCall:(NSDictionary *)parameters fromURL:(NSString *)url completionHandler:(void (^)(NSString *responseString, NSError *error))completionHandler {

    // create your request here ...

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (completionHandler) {
            if (error) {
                completionHandler(nil, error);
            } else {
                NSError *parseError = nil;
                NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];

                completionHandler(responseDictionary[@"response"], parseError);
            }
        }
    }];

    [dataTask resume];

    return dataTask;
}

În ceea ce privește întrebarea dvs. de bază, dacă o metodă precum postCall are sens, da, cred că este perfect logic ca detaliile de creare a cererii să fie incluse într-o singură metodă. Rezerva mea minoră cu privire la implementarea dvs. a fost decizia dvs. de a face din aceasta o metodă de clasă mai degrabă decât o metodă de instanță. În prezent, creați o nouă clasă NSURLSession pentru fiecare cerere. Aș sugera să faceți postCall o metodă de instanță (a unui singleton, dacă doriți) și apoi să salvați sesiunea ca o proprietate de clasă, pe care să o setați o dată și apoi să o reutilizați la interogările ulterioare.

Comentarii

  • Multe mulțumiri pentru eforturile depuse, dar, din păcate, nu pot verifica răspunsul în această seară, deoarece sunt puțin ocupat. Cu toate acestea, îl voi verifica mâine. +1 oricum. –  > Por Carol Smith.
  • @Rob și am corectat și eu erorile din original. –  > Por Alex Zavatone.
  • Mulțumesc, Rob. Ieri am reparat o mulțime de erori în postări cu gramatică teribilă, formatare nestandardizată a codurilor și probabil că pur și simplu am văzut erori și le-am reparat. În alte postări, vreau înapoi și am corectat greșelile de ortografie ale posterului original și probabil că nu le-am văzut pe cele din acest fir. –  > Por Alex Zavatone.
Sunny Shah

Ar trebui să folosiți o metodă de bloc.

Mai întâi definiți un bloc

typedef void (^OnComplete) (NSData *data);

Utilizați următoarea metodă

+ (void)postCall:(NSDictionary *)parameters fromURL:(NSString *)url withBlock:(OnComplete)block; {

     NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
        NSMutableArray *pairs = [[NSMutableArray alloc]init];
        for(NSString *key in parameters){
            [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, parameters[key]]];
        }
        NSString *requestParameters = [pairs componentsJoinedByString:@"&"];
        NSURL *myURL = [NSURL URLWithString:url];
        NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:myURL];
        [urlRequest setHTTPMethod:@"POST"];
        [urlRequest setHTTPBody:[requestParameters dataUsingEncoding:NSUTF8StringEncoding]];
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            block(data);
        }];
        [dataTask resume];
   }

Comentarii

  • Apreciez foarte mult eforturile depuse. Îmi pare rău, dar nu voi putea să verific în seara asta, deoarece sunt ocupat. Cu toate acestea, o voi verifica mâine. +1 oricum. –  > Por Carol Smith.