2012-07-16 21 views
11

Spędziłem zbyt dużo czasu, krzycząc sobie z głowy na NSURLCache, więc oferuję tę radę w nadziei, że inni mogą uniknąć mojego nieszczęścia.NSURLCache zapewniający niespójne wyniki na iOS5, pozornie losowo

Wszystko zaczęło się dość rozsądnie. Mój nowy projekt aplikacji dotyczy tylko iOS 5 i nowszych wersji, więc pomyślałem, że mogę skorzystać z nowej implementacji NSURLCache dla wszystkich moich potrzeb związanych z buforowaniem sieci. Potrzebowałem niestandardowej podklasy NSURLCache, aby obsłużyć kilka specjalnych zadań, ale to wszystko wydawało się być obsługiwane przez API. Szybkie odczytu dokumentacji i jestem off do wyścigów:

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

I postać cache 8MB jest w porządku, aby rozpocząć, a ja jego kopię z większej pamięci podręcznej dysku, dzięki czemu możemy służyć więcej nasze większe obrazy lokalnie. Łączę resztę kodu sieciowego, aby używać NSURLConnection (w rzeczywistości użyłem MKNetworkKit, ale okazało się to nieistotne) i oczekuję wspaniałych rzeczy z mojej pamięci podręcznej. Oczywiście, wszystkie żądania, które mają być buforowane, są sumiennie zapisywane w pamięci podręcznej, a odpowiedzi są sumiennie wracające szybko, gdy są podawane z pamięci podręcznej. To regularna produkcja Piratów z Penzance z tak wielkim obowiązkiem latania w moim stosie sieciowym.

Z tym, że coś się nie sumuje. Żądania, które mogą być dostarczane z pamięci podręcznej, wciąż wychodzą poza sieć. Z wyjątkiem sytuacji, gdy nie są. Wygląda na całkowicie losowy i sporadyczny, czy pamięć podręczna jest rzeczywiście używana do obsługi żądania. Wyrywam włosy z frustracji i przekopuję dosłownie wszystko, próbując zrozumieć, co się dzieje. Buduję aplikacje testowe, ustalam punkty przerwań w każdym miejscu, łamię ślady pakietów, czytam każde słowo w Internecie, które wspomina o NSURLCache, eksperymentuję z nagłówkami kontroli pamięci podręcznej, komentuję kod, pomijam moją podklasę, a nawet uciekam się do skrupulatnego śledzenia przez montaż dla NSURLCache i jego znajomych z sieci CFNet, aby spróbować zrozumieć, co kryje się pod tajemniczą logiką. Znacznie poszerzam swoją wiedzę na temat konwencji wywoływania ARM i Objective-C i uczę się trochę o debugowaniu niskiego poziomu, ale nigdy nie odkrywam, co się dzieje. Cała sprawa jest bardziej podobna do Iolanthe Nightmare Song niż łagodna dyktatura Króla Piratów i jestem prawie na skraju wyrzucenia wszystkiego.

Wersja TL/DR: Wydaje się, że NSURLCache działa, ale losowo nie zwraca wyników z pamięci podręcznej, mimo że ma je dostępne.

+0

Czy próbujesz użyć buforowania dla NSURLConnection, UIWebView, lub obu? Omówiłem buforowanie UIWebView z programistą Safari w WWDC kilka miesięcy temu. Powiedział, że istnieje rodzaj dwuwarstwowej pamięci podręcznej. Z moich własnych testów debugowania odkryłem, że '+ [NSURLCache sharedURLCache]' jest sprawdzany przed sprawdzeniem pamięci podręcznej Safari na poziomie OS. Jednak odpowiedź nie zostanie zapisana w pamięci podręcznej w udostępnianej pamięci podręcznej aplikacji i kto wie, jak zachowuje się pamięć podręczna na poziomie systemu operacyjnego. – goldierox

+0

Interesujące. Naprawdę skupiłem się tylko na stronie NSURLConnection, ponieważ nasza aplikacja nie wykorzystuje interfejsu UIWebView. Pamiętam, że czytałem, że pamięć podręczna Safari na poziomie systemu operacyjnego nie była używana przez aplikacje, ale uważam, że tak nie jest, szczególnie w przypadku interfejsu UIWebView. –

Odpowiedz

9

W końcu próbuję różnych permutacji wszystkich bitów, z którymi błądziłem. Ustawiłem rozmiar pamięci i pamięci podręcznej dysku na 8 MB.

Lo and beold, cała dziwność zniknie! Wszystko, co powinno zostać zbuforowane, zostaje zapisane. A wszystko, co ma pochodzić z pamięci podręcznej, jest odbierane bez żądań sieci.

Wygląda na to, że implementacja NSURLCache w iOS5 nadal nie jest kompletna. Używa pamięci podręcznej dysku i pamięci (w przeciwieństwie do iOS4 i wcześniejszych wersji, które zaimplementowały tylko pamięć podręczną w pamięci), ale w rzeczywistości nie przechodzą one przez pamięć podręczną do pamięci podręcznej dysku, gdy brakuje tego żądania. Jako taki, jest to w zasadzie ślepy traf (dobrze, ślepy traf, na który wpływa cała twoja sieć i użycie pamięci podręcznej), czy dana odpowiedź ma miejsce w pamięci, czy nie w odpowiednim momencie. Jest to prawdopodobnie przydatne w celu zmniejszenia IO pliku pamięci flash na urządzeniu, ale szalenie nieprzyjemne, jeśli oczekujesz racjonalnego zachowania z klasy.

I tak z roześmianą piosenką i wesołym tańcem sprawdzam poprawkę w dwóch liniach i robię pośpiesznie do baru, ostatecznie dzieląc się tą wiedzą z SO (i raportem o błędzie Apple) w nadziei, że nikt inny nie ma znów przejść przez ten ból.

Morał z tej opowieści o niedoli: dziwne i złe rzeczy się zdarzą, jeśli spróbujesz użyć NSURLCache na iOS5 z dyskiem o pojemności większej niż pojemność pamięci. Nie rób tego. I unikaj tworzenia wrogów magicznych wróżek.

+0

Z przykrością muszę stwierdzić, że to nie działa dla mnie. – bogardon

+0

To sprawiło, że było o wiele lepiej dla mnie, ale i tak miałem jeszcze trochę dziwności. Wygląda na to, że istnieje kilka poważnych problemów z synchronizacją (?) Z NSURLCache. Złożyłem radar, aw międzyczasie skończyłem przenosić cały mój obraz do całkiem zhakowanego widelca SDWebImage (https://github.com/rs/SDWebImage), który przynajmniej zachowuje się deterministycznie. –

2

FWIW oto moje ostateczne rozwiązanie:

https://gist.github.com/3245415

wymaga korzystania FMDB, ale wyniki są bardzo dobre.

+0

Przyjemne podejście. Pomyślałem o próbowaniu czegoś takiego, ale ostatecznie byłem nieufny wobec mucking z SQLite DB osobiście kiedy to było wyraźnie zachowujące się tak nieprzewidywalnie. Martwiłbym się problemami związanymi z synchronizacją z Twoją poprawką, ale może wszystko to sprawdza się w praktyce. Jak wspomniałem powyżej, korzystałem z podpartego przez NSCache widelca SDWebImage (patrz żądania ściągania), aby obsłużyć buforowanie obrazu i byłem bardzo zadowolony z wyników. –

Powiązane problemy