iOS NSURLSessionのピット(The data couldn’t be read because it isn’t in the correct format)

4141 ワード

概要

  • ネットワークリクエスト時に,タイトルのようなerrorが出現し,原因が多く,ここでは一度自分が遭遇した原因を記録する.
  • コードは次の
  • です.
    #pragma mark -  
    - (void)test{
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
        NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegateObject delegateQueue:[NSOperationQueue mainQueue]];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:@"api.com"];
        request.HTTPBody = para// 
        NSURLSessionTask *task = [session dataTaskWithRequest:request];
        [task resume];
    }
    
    #pragma mark - NSURLSessionDelegate method
    -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
    {
        DeLog(@"1。 %s",__FUNCTION__);
        completionHandler(NSURLSessionResponseAllow);
    }
    -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
    {
        NSError *error;
            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:self.recevieData options:NSJSONReadingMutableLeaves error:&error];
            if (error)
            {
                NSLog(@"initSDK error === %@",error.localizedDescription);
            }
    }
    -(void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error{
    }
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
    {
        [session finishTasksAndInvalidate];
    }
    

    印刷結果:initSDK error === The data couldn’t be read because it isn’t in the correct format

    ぶんせき

  • 分析の結果、-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)dataのdataは完全なデータではない場合がある.
  • [NSByteCountFormatter stringFromByteCount:data countStyle:NSByteCountFormatterCountStyleFile]印刷、完全data=2KB、エラーdata=1KB.
  • によって取り出されたdata=2KB/data=1KBはランダムに現れる.
  • dataは実はjsonで、それぞれdataNSDictionaryNSStringに変えて、NSDictionary=nilで、NSStringは値がありますが、完全なjsonの一部
  • です.
  • 私の例では、data=1KBのとき、-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)dataは実際に2回呼び出されます.私は前後2回のdataをつなぎ合わせて、ちょうど完全なjsonです.一方、data=2KBの場合、
  • は1回のみ呼び出される.
  • の答えは明らかです.

  • 解決する

  • -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data得られるdataは必ずしも最終的なdataではなく、複数回呼び出される可能性がある以上、純粋で完全なjsonを得るためには、NSURLSessionDelegateの多くの方法の中で呼び出さなければならない.また、要求プロセス全体が完了した後、最後に呼び出される方法であり、この方法はまだ1回しか呼び出されない.
  • - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)errorはこの問題を完璧に解決した.通常、sessionを放出するので、この方法にも含まれます.
  • 上記の例の解決コード
  • #pragma mark - NSURLSessionDelegate method
    #pragma mark -  , data
    NSMutableData *_data;
    -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
    {
         if(_data)
       {
         _data = [[NSMutableData alloc] init];
       }
         [_data appendData:data];
    }
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
    {
        #pragma _data, json
         NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:_data options:NSJSONReadingMutableLeaves error:&error];
        [session finishTasksAndInvalidate];
    }
    
  • は、ループ要求5000回を経る、data=1KBが発生しない場合
  • である.
  • エージェントを使用しない方式、blockを使用する方式、blockのdataはこのような状況は発生しません.