Я считаю, что код взят из примера кода SimpleURLConnections от Apple. Вот прямая цитата из метода NSURLConnection от Apple: connection: didReceiveData: "
"Делегат должен объединить
содержимое каждого доставленного объекта данных
создать полные данные для
Загрузка URL. "
NSData не предоставляет методы для постепенной записи в файл, он записывает все сразу, поэтому я считаю, что этот метод постепенной записи в NSOutputStream, здесь называемый fileStream, является правильным. Использование dataLength в этом коде будет только возвращать длину данных, которые были отправлены из NSURLConnection делегату за один вызов «connection: didReceiveData:», а не общую длину данных для всего соединения. Для этого я добавил дополнительные свойства:
@property (nonatomic, assign) long long dataWrittenForWholeConnection;
@property (nonatomic, assign) long long dataLengthOfWholeConnection;
В связи: didReceiveResponse: Я использовал метод NSURLResponse Ожидаемый размер содержимого для получения правильной оценки размера файла принимаемых данных для всего соединения.
self.dataWrittenForWholeConnection = 0;
self.dataLengthOfWholeConnection = [httpResponse expectedContentLength];
В связи: didReceiveData: я изменил следующее:
// bytes written for current "connection:didReceiveData:" call
bytesWrittenSoFar += bytesWritten;
// cumulative data written for connection so far
self.dataWrittenForWholeConnection += bytesWritten;
// also update the progress bar
if (self.dataLengthOfWholeConnection != NSURLResponseUnknownLength) {
self.progressView.progress =
((float)self.dataWrittenForWholeConnection / (float)self.dataLengthOfWholeConnection);
}
К концу соединения это должно быть верно:
assert(dataWrittenForWholeConnection == dataLengthOfWholeConnection);
Вот распечатка из того же кода SimpleURLConnections с моими изменениями, чтобы показать, что на самом деле происходит:
connection:didReceiveResponse:
Full size of data is 8789 bytes
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.160200
1408 bytes of data were written, 1408 bytes so far
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.320401
1408 bytes of data were written, 2816 bytes so far
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.480601
1408 bytes of data were written, 4224 bytes so far
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.640801
1408 bytes of data were written, 5632 bytes so far
connection:didReceiveData:
Data has 1408 bytes
Progress bar is at: 0.801001
1408 bytes of data were written, 7040 bytes so far
connection:didReceiveData:
Data has 1749 bytes
Progress bar is at: 1.000000
1749 bytes of data were written, 8789 bytes so far
connectionDidFinishLoading:
Connection Finished. 8789/8789 bytes of data were written.
Кроме того, метод NSOutputStream «write: maxLength:» возвращает «количество фактически записанных байтов», поэтому по какой-то причине он может решить не записывать все данные сразу за один вызов «connection: didReceiveData:» , таким образом, использование цикла do / while для проверки этого. Но в этом примере он записывает все данные за одну итерацию do / while.
Кроме того, вместо этого вы можете использовать NSFileHandle, и при этом всегда будут записываться все данные, отправляемые с каждым соединением: didReceiveData: call, также оно является инкрементным. Обратите внимание, что writeData: является синхронным.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// write data to file handler
unsigned long long dataLength = [data length];
NSLog(@"Writing %qu bytes at %qu bytes", dataLength, [self.fileHandle offsetInFile]);
[self.fileHandle writeData:data];
NSLog(@"Wrote %qu bytes, now at %qu bytes", dataLength, [self.fileHandle offsetInFile]);
}