1

プロジェクト用に networkUtil を開発しています。URL を取得し、NSURLSessionDataTask を使用してその URL から受け取った JSON を返し、サーバーから JSON を取得するメソッドが必要です。メソッドは次のとおりです。

+ (NSDictionary*) getJsonDataFromURL:(NSString *)urlString{
    __block NSDictionary* jsonResponse;
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"%@", jsonResponse);
    }];

    [dataTask resume];

    return jsonResponse;
}

問題は、メソッド内のcompletionHandlerとメソッド自体が異なるスレッドで実行され、最後の行で jsonResponse が常にnilであることです。

urlStringから返された json でjsonResponseを設定するにはどうすればよいですか? この問題のベスト プラクティス は何ですか?

4

4 に答える 4

3

NSURLSession で実行されているブロックが別のスレッドで実行されています - メソッドはブロックが終了するのを待ちません。

ここには2つのオプションがあります

最初のもの。NSNotification を送信

+ (void) getJsonDataFromURL:(NSString *)urlString{
       NSURLSession *session = [NSURLSession sharedSession];
       NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
           NSDictionary* jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
           NSLog(@"%@", jsonResponse);

           [[NSNotificationCenter defaultCenter] postNotificationName:@"JSONResponse" object:nil userInfo:@{@"response" : jsonResponse}];
       }];

       [dataTask resume];
}

2つ目。このユーティリティ メソッドへの過去の完了ブロック

+ (void) getJsonDataFromURL:(NSString *)urlString
            completionBlock:(void(^)(NSDictionary* response))completion {
       NSURLSession *session = [NSURLSession sharedSession];
       NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
           NSDictionary* jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
           NSLog(@"%@", jsonResponse);

           completion(jsonResponse);
       }];

       [dataTask resume];
}
于 2015-07-02T08:08:38.440 に答える
0

これは、「非同期呼び出し」の意図された動作です。呼び出しが完了すると、呼び出しスレッドをブロックしませんが、渡されたブロックを実行します。

ブロックで結果を取得した後に実行する必要があるコードを追加するだけです。

代わりに…</p>

+ (NSDictionary*) getJsonDataFromURL:(NSString *)urlString
{
  __block NSDictionary* jsonResponse;
  NSURLSession *session = [NSURLSession sharedSession];
  NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:
  ^(NSData *data, NSURLResponse *response, NSError *error) 
  {
    jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSLog(@"%@", jsonResponse);
  }];

  [dataTask resume];

  return jsonResponse;
}
…
NSDictionary* jsonResponde = [self getJsonDataFromURL:url]; // BTW: get infringes the naming rules of Objective-C
// The code that has to be executed is here

… これをして:

+ (void) getJsonDataFromURL:(NSString *)urlString
{
  NSURLSession *session = [NSURLSession sharedSession];
  NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:
  ^(NSData *data, NSURLResponse *response, NSError *error) 
  {
    NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSLog(@"%@", jsonResponse);
    // Place the code to be executed here <-----
  }];

  [dataTask resume];
}
…
[self getJsonDataFromURL:url]; // BTW: get infringes the naming rules of Objective-C
// No code here any more

によって実行されるコード-getJsonDataFromURL:が呼び出し元に依存する場合は、それを引数としてメソッドに渡し、指定された場所で実行します。そのための助けが必要な場合は、お知らせください。そのためのコードを追加します。

もう 1 つの解決策は、セマフォを使用して、完了ハンドラが実行されるまで待機することです。ただし、これは UI をブロックするため、意図しない方法です。

于 2015-07-02T08:15:29.337 に答える