NSURLSession - данные равны нулю

У меня возникла проблема при попытке получить данные с помощью методов делегата NSURLSession. Я придумал эту ошибку:

"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'"

Чего я не понимаю, так это

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {

    CGFloat percentDone = (double)totalBytesWritten/(double)totalBytesExpectedToWrite;
    NSLog(@"Pourcentage: %f", percentDone);
}

возвращает 1.000000, и вызывается следующий метод делегата

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    // Parse the JSON that came in

    NSLog(@"DidComplete"); --> I can see this message

    if (error) {
        NSLog(@"Error in finishLoading: %@", error.localizedDescription); --> but this message is not displayed. There is no error, only data returning nil resulting in a crash...
    }
    else {
    ....
}

Но следующие методы не вызываются

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *) response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {

    NSLog(@"DidReceiveResponse"); --> not displayed

    completionHandler(NSURLSessionResponseAllow);
}


- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {

    NSLog(@"DidReceiveData. Data: %@", data); --> not displayed

    _downloadedData = [[NSMutableData alloc] init];
    [_downloadedData appendData:data];
}

однако его следует вызывать до didCompleteWithError, не так ли? Я предполагаю, что другие методы, отвечающие за добавление данных, не могут быть вызваны, и тогда данные равны нулю.

Я уверен, что могу получить данные на стороне сервера, поскольку, когда я использую блочный метод (а не методы делегата), NSData соответствует тому, что я ищу.

Странно то, что эта ошибка возникает после того, как я изменил сеанс конфигурации следующим образом:

NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession2 = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];

    NSURL *url = [NSURL URLWithString:@"http://localhost:8888/download_list.php"];

    NSURLSessionDownloadTask *dataTask = [defaultSession2 downloadTaskWithURL:url];

Когда это было так, я мог видеть NSData, который был получен с сервера.

NSURLSessionDataTask *dataTask = [defaultSession2 dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if(error == nil) {
         NSString * text = [[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding];
         NSLog(@"Data = %@",text); -> text corresponds to the data I am looking for
    }
}];

Однако нельзя было вызвать делегата с блоком.

Любая идея, как «данные» исчезают? Или я должен что-то изменить, когда не использую блок?

Спасибо за помощь!


person Trichophyton    schedule 15.11.2016    source источник
comment
Все в порядке, я был глуп, это был NSURLSessionDownloadTask вместо NSURLSessionDataTask... Однако у меня есть странное сообщение: nw_host_stats_add_src recv too small, получил 24, ожидал 28. Кто-нибудь знает, что это значит?   -  person Trichophyton    schedule 15.11.2016
comment
К сожалению, это ничего не меняет...   -  person Trichophyton    schedule 15.11.2016
comment
Странное сообщение — новая проблема. Удалите Q и создайте новый. Задача читателей не состоит в том, чтобы собрать воедино настоящий Q.   -  person Amin Negm-Awad    schedule 15.11.2016
comment
Я не очень понял, какая цель с новой очередью? Я изменил dataTask, и были вызваны методы делегата, спасибо.   -  person Trichophyton    schedule 16.11.2016
comment
Не очередь, а скорее вопрос. Он говорит, что если у вас есть вопрос о каком-то странном сообщении в журнале, это совершенно другая проблема, и ее следует опубликовать как отдельный вопрос, а не задавать в комментариях под этим вопросом. Похоже, вопрос здесь заключался в том, почему я не вижу вызываемых методов делегата?, на что ответ заключается в том, что вы использовали представление обработчика завершения dataTaskWithURL.   -  person Rob    schedule 16.11.2016


Ответы (1)


Методы делегата didReceiveResponse и didReceiveData не будут вызываться, если вы вызываете dataTaskWithURL следующим образом:

NSURLSessionDataTask *dataTask = [defaultSession2 dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    ...
}];

Вы предоставляете обработчик завершения, запрашивая его для захвата response и data для вас. Итак, для этого он не будет вызывать методы делегата.

Если вы хотите, чтобы ваши методы делегата вызывались, вы должны просто:

NSURLSessionDataTask *dataTask = [defaultSession2 dataTaskWithURL:url];

Откровенно говоря, в настоящее время вы не делаете ничего существенного в этих методах, поэтому мне интересно, почему вы хотите использовать методы делегата, а не обработчик завершения. Шаблон обработчика завершения проще.


Кстати, если вы собираетесь использовать эти методы, убедитесь, что добавляется только didReceiveData. Создайте экземпляр изменяемого объекта данных в didReceiveResponse. Для получения всего ответа может потребоваться более одного вызова didReceiveData, а исходный пример кода будет усекать результаты. Вы, вероятно, хотите сделать что-то вроде:

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *) response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    NSLog(@"DidReceiveResponse");                 // will now be displayed

    _downloadedData = [[NSMutableData alloc] init];

    completionHandler(NSURLSessionResponseAllow);
}


- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
    NSLog(@"DidReceiveData. Data: %@", data);     // will now be displayed

    [_downloadedData appendData:data];
}
person Rob    schedule 16.11.2016