Я пишу клиент для iPhone, который загружает вещи из сети. Поскольку сотовая сеть не такая быстрая, а файлы могут быть большими, я хотел улучшить счетчик активности с помощью индикатора выполнения.
Пока все хорошо, я используя NSURLConnection и проверяя заголовок Content-Length
, чтобы увидеть, сколько байтов я буду загружать. Затем в обратном вызове : didReceiveData:
я добавляю полученные данные в мой объект NSMutableData
, и там я могу отследить размер загруженного контента до ожидаемых байтов.
Это все работает, пока у вас нет сервера, который поддерживает сжатие GZIP. Сервер, использующий сжатие gzip, будет объявлять x байтов в качестве размера контента. Однако, поскольку NSURLConnection выполняет декомпрессию за кулисами, данные, переданные обратному вызову didreceiveData , уже расширены. Следовательно, ожидаемые загруженные байты меньше, чем фактически принятые байты, в пропорции степени сжатия для файла.
Это означает, что индикатор выполнения переполняется , поскольку ожидаемое количество байтов достигается намного раньше, чем ожидалось. Что-то, что я мог бы сделать, когда я управляю сервером, это отправить специальные заголовки для содержимого gzip, чтобы избежать распаковки, выполняемой NSURLConnection, но я не могу контролировать все серверы в Интернете.
Есть ли какой-то скрытый метод для отчета NSURLConnection, чтобы сообщить переданные байты, а не расширенные байты? Должен ли я кодировать свое собственное NSURLConnection, чтобы отслеживать переданные байты и самостоятельно распаковывать данные gzip для точного индикатора выполнения? Может быть есть альтернативный базовый API нижнего уровня?
Используйте библиотеку ASIHTTPRequest. Это мой общий ответ почти на все вопросы «как мне стать веб-клиентом на iPhone», но в данном случае он особенно полезен.
Проверьте это:
-(void)viewDidLoad {
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:myNSURLObject];
request.delegate = self;
request.downloadProgressDelegate = self.myUIProgressViewInstance;
//it'll update that progress bar with a percentage complete automatically!
//or give it any custom class that responds to -progress!
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
//do whatever to process the data you just got
}
ASIHTTP упрощает многие мощные сетевые операции. Я большой поклонник.
IIRC, вы должны использовать метод -expectedContentLength
из NSURLResponse
, который, по моему тестированию, возвращает NSURLResponseUnknownLength
(-1) для сжатого содержимого.
Одним из способов обхода проблемы было бы отключить отправку сжатого содержимого, вручную установив заголовок Accept-Encoding
:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:yourURL];
[request setValue:@"" forHTTPHeaderField:@"Accept-Encoding"];
, но, конечно, это лишает смысла сжатие содержимого. : /
(Если есть лучшее решение (которое, надеюсь, не предполагает перехода на более низкий уровень, чем материал NSURL *
), я бы тоже хотел об этом узнать…)