2015-11-29 2 views
1

Je suis un débutant en Objective C et je cherche à faire deux HTTP GET consécutifs (l'un après l'autre). Ce que j'ai jusqu'ici est que j'ai un NSURLSessionDataTask à l'intérieur du bloc d'achèvement de la première NSURLSessionDataTask. Cela rend mon code un peu illisible, alors je me demandais quelle est la meilleure façon de le faire? Voici quelques exemples de code:NSURLSessionDataTask imbriqué pour deux GET HTTP consécutifs

{ 
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];  
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; 

    NSMutableURLRequest *url_request_1 = [NSMutableURLRequest requestWithURL:@"some_url_1"]; 
    [url_request_1 setHTTPMethod:@"GET"]; 

    NSURLSessionDataTask *url_task_1 = [session 
     dataTaskWithRequest:url_request_1 
     completionHandler:^(NSData *data1, 
     NSURLResponse *response1, 
     NSError *error1) { 

      if(data1 !=nil){ 
       // Evaluate some_url_2 from the response of url_task_1 

       NSMutableURLRequest *url_request_2 = [NSMutableURLRequest requestWithURL:@"some_url_2"]; 
       [url_request_2 setHTTPMethod:@"GET"]; 

       NSURLSessionDataTask *url_task_2 = [session 
        dataTaskWithRequest:url_request_2 
        completionHandler:^(NSData *data2, 
        NSURLResponse *response2, 
        NSError *error2) { 

         if(data2 !=nil){  
          // Process data here     
         } else { 
          // Handle error here. 
          return; 
         } 
        }]; 

       [urlRequest2 resume]; 
      } 
      else{ 
       // Handle error here 
       return; 
      } 
     }]; 

    [url_task_1 resume]; 
} 
+0

@Velox - Modifier manuellement l'indentation de la question peut l'avoir rendu plus lisible, mais vous êtes en train d'obscurcir l'un des problèmes sous-jacents de la façon dont Tywin a écrit son code. – Rob

Répondre

1

Ceci est rendu un peu moins difficile à manier en changeant votre style d'indentation et à l'aide modèle de sortie précoce.

- (void)performRequestsWithCompletion:(void (^ _Nonnull)(NSDictionary *, NSError *))completion { 
    NSMutableURLRequest *request1 = [NSMutableURLRequest requestWithURL:firstURL]; 

    NSURLSessionDataTask *task1 = [self.session dataTaskWithRequest:request1 completionHandler:^(NSData *data1, NSURLResponse *response1, NSError *error1) { 
     if (!data1) { 
      // handle error here, then return 
      completion(nil, error1); 
      return; 
     } 

     NSMutableURLRequest *request2 = [NSMutableURLRequest requestWithURL:secondURL]; 

     NSURLSessionDataTask *task2 = [self.session dataTaskWithRequest:request2 completionHandler:^(NSData *data2, NSURLResponse *response2, NSError *error2) { 
      if (!data2) { 
       // handle error here, then return 
       completion(nil, error2); 
       return; 
      } 

      // handle parsing `data2` here 
      NSDictionary *result = ...; 
      completion(result, nil); 
     }]; 

     [task2 resume]; 
    }]; 

    [task1 resume]; 
} 

Remarque, j'ai ajouté un gestionnaire d'achèvement ici, parce que c'est l'un des meilleurs modèles pour laisser tout auteur de cette demande que tout est fait. Clairement, mes paramètres de bloc supposaient que vous retourniez un dictionnaire, donc vous devriez changer ceci pour être quel (s) type (s) votre routine retourne.

Sinon (et surtout si vous faites beaucoup plus que deux appels de service Web successifs), vous pouvez le décomposer en méthodes distinctes:

- (void)performRequestsWithCompletion:(void (^ _Nonnull)(NSDictionary *, NSError *))completion { 
    [self performFirstRequestWithCompletion:completion]; 
} 

- (NSURLSessionTask *)performFirstRequestWithCompletion:(void (^ _Nonnull)(NSDictionary *, NSError *))completion { 
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:firstURL]; 

    NSURLSessionTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
     if (!data || error) { 
      // Handle error here 
      completion(nil, error); 
      return; 
     } 

     // Evaluate some_url_2 from the response of url_task_1 
     [self performSecondRequestWithCompletion:completion]; 
    }]; 
    [task resume]; 

    return task; 
} 

- (NSURLSessionTask *)performSecondRequestWithCompletion:(void (^ _Nonnull)(NSDictionary *, NSError *))completion { 
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:secondURL]; 

    NSURLSessionTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
     if (!data || error) { 
      // Handle error here, and return 
      completion(nil, error); 
      return; 
     } 

     // Process data here 

     NSDictionary *result = ...; 
     completion(result, nil); 
    }]; 

    [task resume]; 

    return task; 
} 

Avec ce modèle, peu importe combien dépendant appels que vous avez, vous ne finirez pas avec la tour de blocs imbriqués.


Dans l'intérêt de l'exhaustivité, d'autres modèles qui permettent d'éviter ces tours de blocs intra-blocs comprennent NSOperation modèles et approches tiers comme terme/promesses (par exemple PromiseKit). Ceux-ci sont au-delà de la portée de cette question, mais ils valent la peine d'être considérés si vous le faites beaucoup.

+0

Très bien, je suppose que le séparer en méthodes séparées aurait plus de sens. J'espère que c'est une bonne pratique. Merci Rob! – Tywin

+0

@Tywin - Non merci nécessaire. Voir [Que dois-je faire quand quelqu'un répond à ma question?] (Http://stackoverflow.com/help/someone-answers) – Rob

+0

Je préfère votre deuxième scénario. Il est bon de casser deux tâches dans deux méthodes différentes. Si j'ajoute 'dispatch_async (dispatch_get_main_queue()' dans NSURLSessionDataTask va-t-il créer un problème? –