NSURLCache дает противоречивые результаты на iOS5, по-видимому, случайным образом

Я только что провел слишком много времени, крича о NSURLCache, поэтому я даю этот совет в надежде, что другие смогут избежать моей неудачи.

Все началось достаточно разумно. Мой новый проект приложения предназначен только для iOS 5 и выше, поэтому я подумал, что смогу воспользоваться новой реализацией NSURLCache для всех своих потребностей в веб-кэшировании. Мне нужен был собственный подкласс NSURLCache для выполнения нескольких специальных задач, но все это, казалось, поддерживалось API. Быстрое чтение документации, и я отправляюсь в гонки:

[NSURLCache setSharedURLCache:[[MyCustomCache alloc] initWithMemoryCapacity:8 * 1024 * 1024 //8mb 
                                                                    diskCapacity:32 * 1024 * 1024 // 32mb 
                                                                        diskPath:@"webcache.db"]];

Я полагаю, что 8-мегабайтный кеш подойдет для начала, и я подкреплю его дисковым кешем большего размера, чтобы мы могли обслуживать больше наших больших изображений локально. Я подключаю остальную часть своего сетевого кода для использования NSURLConnection (на самом деле я использовал MKNetworkKit, но это оказалось неуместным), и ожидайте многого от моего тайника. Разумеется, все запросы, которые должны быть кэшированы, должным образом сохраняются в кеше, а ответы должным образом быстро возвращаются обратно, когда они обслуживаются из кеша. Это обычная постановка «Пиратов Пензанса», и в моем сетевом стеке так много обязанностей.

Только что-то не сходится. Запросы, которые могут быть обслужены из кэша, по-прежнему отправляются по сети. За исключением случаев, когда это не так. Кажется, что кеш действительно используется для обслуживания запроса, и это кажется совершенно случайным и прерывистым. Я в отчаянии рву на себе волосы и копаюсь буквально во всем, пытаясь понять, что происходит. Я создаю тестовые приложения, повсюду устанавливаю точки останова, разрываю трассировку пакетов, читаю каждое слово в Интернете, в котором упоминается NSURLCache, экспериментирую с заголовками управления кешем, комментирую код, обхожу свой подкласс и даже прибегаю к кропотливой трассировке через сборка для NSURLCache и его друзей из CFNetworking, чтобы попытаться понять, какая загадочная логика скрывается за ними. Я значительно улучшил свои знания о соглашениях о вызовах ARM и Objective-C и немного узнаю о низкоуровневой отладке, но на самом деле ничего не понимаю в том, что происходит. Все это больше похоже на Песню кошмаров Иоланты, чем на мягкую диктатуру Короля пиратов и меня практически на грани того, чтобы все бросить.

Версия TL/DR: кажется, что NSURLCache работает, но случайным образом не возвращает кэшированные результаты, даже если они доступны.


person Zach Lipton    schedule 16.07.2012    source источник
comment
Вы пытаетесь использовать кэширование для NSURLConnection, UIWebView или для обоих? Я обсуждал кэширование UIWebView с разработчиком Safari на WWDC несколько месяцев назад. Он сказал, что там вроде двухслойный кэш. Из моих собственных отладочных тестов я обнаружил, что +[NSURLCache sharedURLCache] проверяется перед проверкой кеша Safari на уровне ОС. Однако ответ не будет кэшироваться в общем кеше вашего приложения, и кто знает, как ведет себя кеш уровня ОС.   -  person goldierox    schedule 15.08.2012
comment
Интересный. Я действительно сосредоточился только на стороне NSURLConnection, так как наше приложение не особо использует UIWebView. Я помню, как читал, что кеш Safari на уровне ОС не использовался приложениями, но я могу поверить, что это не так, особенно для UIWebView.   -  person Zach Lipton    schedule 15.10.2012


Ответы (2)


В конце концов, я пробую другую перестановку всех битов, с которыми я возился. Я установил размеры кэша памяти и диска на 8 МБ.

Вот и все странности исчезают! Все, что должно кэшироваться, сохраняется. И все, что должно поступать из кеша, обслуживается без сетевых запросов.

Похоже, реализация NSURLCache в iOS5 еще не завершена. Он использует кеш диска и памяти (в отличие от iOS4 и более ранних версий, в которых реализован только кеш в памяти), но на самом деле он не проходит через кеш памяти в кеш диска, когда запрос отсутствует. Таким образом, это в основном слепая удача (ну, слепая удача, на которую влияет вся ваша другая сеть и использование кеша), независимо от того, оказывается ли данный ответ в памяти или нет в нужный момент. Это, вероятно, полезно для уменьшения операций ввода-вывода файлов флэш-памяти на устройстве, но безумно неприятно, если вы ожидаете рационального поведения от класса.

Итак, под веселую песню и веселый танец, я проверяю свое двухстрочное исправление и спешу в бар, в конце концов делясь этими знаниями с SO (и отчетом об ошибке Apple) в надежде, что никому больше не придется проходить через это. опять боль.

Мораль этой печальной истории: странные и злые вещи произойдут, если вы попытаетесь использовать NSURLCache на iOS5 с объемом диска, превышающим объем памяти. Не делай этого. И не наживайте врагов из волшебных фей.

person Zach Lipton    schedule 16.07.2012
comment
Это сделало мои вещи намного лучше для меня, но у меня все еще были некоторые странности даже после этого. Похоже, есть серьезные проблемы с синхронизацией (?) с NSURLCache. Я зарегистрировал радар, а тем временем переместил все кеширование своих изображений в изрядно потрепанный форк SDWebImage (github.com/rs/SDWebImage), который, по крайней мере, ведет себя детерминировано. - person Zach Lipton; 26.07.2012

FWIW вот мое окончательное решение:

https://gist.github.com/3245415

это требует использования FMDB, но результаты довольно хорошие.

person bogardon    schedule 07.08.2012
comment
Хороший подход. Я думал о том, чтобы попробовать что-то подобное, но в конечном итоге опасался возиться с SQLite DB, когда он явно вел себя так непредсказуемо. Я бы беспокоился о проблемах синхронизации с вашим исправлением, хотя, может быть, на практике все получится. Как я сказал выше, я использовал форк SDWebImage с поддержкой NSCache (см. пул-реквесты) для обработки кэширования изображений и был очень доволен результатами. - person Zach Lipton; 08.08.2012