У меня есть приложение, которое успешно использует синхронные методы для загрузки файлов (NSData initWithContentsOfURL и NSURLConnection sendSynchronousRequest), но теперь мне нужно поддерживать большие файлы. Это означает, что мне нужно бить поток на диск. Несмотря на то, что потоковая передача на диск и становление асинхронными должны быть полностью ортогональными концепциями, API Apple заставляет меня идти асинхронно для потоковой передачи.Как дождаться загрузки большого файла?
Чтобы быть ясным, мне поручено увеличить загрузку файлов, а не перестраивать все приложение, чтобы они были более асинхронными. У меня нет ресурсов. Но я признаю, что подходы, которые зависят от реорганизации, являются правильными и хорошими.
Так что, если я это сделать:
NSURLConnection* connection = [ [ NSURLConnection alloc ] initWithRequest: request delegate: self startImmediately: YES ];
.. Я в конце концов didReceiveResponse и didReceiveData называется на себя. Отлично. Но, если я пытаюсь сделать это: не
NSURLConnection* connection = [ [ NSURLConnection alloc ] initWithRequest: request delegate: self startImmediately: YES ];
while(!self.downloadComplete)
[ NSThread sleepForTimeInterval: .25 ];
... didReceiveResponse и didReceiveData не называются. И я понял, почему. Как ни странно, асинхронная загрузка происходит в том же основном потоке, который я использую. Поэтому, когда я сплю основную нить, я тоже сплю, что делаю работу. Во всяком случае, я пробовал несколько разных способов достичь того, что я хочу здесь, включая указание NSURLConnection использовать другой NSOperationQueue и даже делать dispatch_async для создания соединения и запускать его вручную (я не вижу, как это не может работать - Я не должен был делать это правильно), но ничего не работает. Редактировать: Что я не делаю правильно, так это понимание того, как работают петли цикла, и что вам нужно запускать их вручную во вторичных потоках.
Каков наилучший способ подождать, пока файл не будет загружен?
Редактировать 3, рабочий код: Следующий код на самом деле работает, но дайте мне знать, если есть лучший способ.
код, выполняемый в оригинальной резьбой, который устанавливает соединение и ждет загрузки для завершения:
dispatch_queue_t downloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(downloadQueue, ^{
self.connection = [ [ NSURLConnection alloc ] initWithRequest: request delegate: self startImmediately: YES ];
[ [ NSRunLoop currentRunLoop ] run ];
});
while(!self.downloadComplete)
[ NSThread sleepForTimeInterval: .25 ];
код, выполняемый в новом потоке, который реагирует на подключение событий:
-(void)connection:(NSURLConnection*) connection didReceiveData:(NSData *)data {
NSUInteger remainingBytes = [ data length ];
while(remainingBytes > 0) {
NSUInteger bytesWritten = [ self.fileWritingStream write: [ data bytes ] maxLength: remainingBytes ];
if(bytesWritten == -1 /*error*/) {
self.downloadComplete = YES;
self.successful = NO;
NSLog(@"Stream error: %@", self.fileWritingStream.streamError);
[ connection cancel ];
return;
}
remainingBytes -= bytesWritten;
}
}
-(void)connection:(NSURLConnection*) connection didFailWithError:(NSError *)error {
self.downloadComplete = YES;
[ self.fileWritingStream close ];
self.successful = NO;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
self.downloadComplete = YES;
[ self.fileWritingStream close ];
self.successful = YES;
}
Если это не проприетарный, мне бы очень хотелось увидеть код в функции didReceiveData. –
@Thunder К счастью. Это в основном то, что я нашел здесь: http://stackoverflow.com/q/4002979/34290, но я также включил его в мой вопрос выше. –
wow sweet! Огромное спасибо. = :-) –