2013-09-26 15 views
8

Dostałem kilka raportów o awariach związanych z UICollectionView w iOS 7. Nie jestem w stanie konsekwentnie odtworzyć tego błędu.UICollectionView crash na unhighlightAllItems

Exception Type: SIGSEGV 
Exception Codes: SEGV_ACCERR at 0x91c4392b 
Crashed Thread: 0 

Application Specific Information: 
*** Terminating app due to uncaught exception '', reason: '' 

Thread 0 Crashed: 
0 libobjc.A.dylib      0x39dd2b26 objc_msgSend + 6 
1 UIKit        0x31fd5eef -[UICollectionView cellForItemAtIndexPath:] + 111 
2 UIKit        0x32060bfd -[UICollectionView _unhighlightItemAtIndexPath:animated:notifyDelegate:] + 149 
3 UIKit        0x32383947 -[UICollectionView _unhighlightAllItems] + 151 
4 UIKit        0x3205f9fb -[UICollectionView touchesBegan:withEvent:] + 367 
5 UIKit        0x31fcb101 forwardTouchMethod + 233 
6 UIKit        0x31fcb101 forwardTouchMethod + 233 
7 UIKit        0x31e3be4b _UIGestureRecognizerUpdate + 5523 
8 UIKit        0x31e73c41 -[UIWindow _sendGesturesForEvent:] + 773 
9 UIKit        0x31e735e7 -[UIWindow sendEvent:] + 667 
10 UIKit        0x31e48a25 -[UIApplication sendEvent:] + 197 
11 UIKit        0x31e47221 _UIApplicationHandleEventQueue + 7097 
12 CoreFoundation      0x2f69e18b __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 
13 CoreFoundation      0x2f69d6e1 __CFRunLoopDoSources0 + 341 
14 CoreFoundation      0x2f69be4f __CFRunLoopRun + 623 
15 CoreFoundation      0x2f606ce7 CFRunLoopRunSpecific + 523 
16 CoreFoundation      0x2f606acb CFRunLoopRunInMode + 107 
17 GraphicsServices     0x342f4283 GSEventRunModal + 139 
18 UIKit        0x31ea8a41 UIApplicationMain + 1137 
19 JackThreadsIpad      0x000922b7 main (main.m:16) 

UICollectionViewCells w aplikacji mają wspólną nadklasę, która zarządza podświetlaniem. Gdy komórka jest podświetlona, ​​zmienia się alfa.

- (void)setHighlighted:(BOOL)highlighted { 
    [super setHighlighted:highlighted]; 

    if (highlighted) { 
     self.alpha = 0.8; 
    } else { 
     self.alpha = 1.0; 
    } 
} 

Czy wywołanie [super setHighlighted: highlighted] może spowodować awarię? Aplikacja została skompilowana i przesłana z XCode 4 i dzieje się tylko na iOS 7. Wszelkie inne sugestie, aby dowiedzieć się, gdzie to się dzieje. Dzięki za pomoc.

Edycja: Udało mi się złapać to w debugerze, ale nadal nie jest powtarzalne. Awaria:

[NSIndexPath section] message sent to deallocated instance XXXXXXXX 
+0

Czy dodałeś punkty przerwania w setHighlighted i cellForItemAtIndexPath? Co się stanie, gdy się przejdzie, gdzie się zawiesza. – Tim

+0

Nie widziałem tej awarii w moim środowisku programistycznym - te i podobne raporty o awariach pojawiły się w programie iTunes Connect i Crittercism. –

+0

Niestety, przegapiłem linię, w której powiedziałeś, że nie możesz jej odtworzyć. – Tim

Odpowiedz

1

Nie jestem pewien po zidentyfikowaniu tylko tego fragmentu kodu. Ale jako sygnał awarii (SIGSEGV) wydaje się ze względu na wyciek pamięci. Po prostu przejdź do ustawień Xcode i wewnątrz Edit Scheme jsut włącz opcję Zombie, a następnie spróbuj odtworzyć awarię. Pokaże ci nazwę klasy kontrolera metody lub wszelkie informacje związane z awarią wewnątrz konsoli Xcode. A także po prostu spróbować zmodyfikować Państwo poniższych warunków: -

- (void)setHighlighted:(BOOL)highlighted { 

    //just comment this line or write this line to the below and check 
    //[super setHighlighted:highlighted]; 
    if (highlighted) { 
     self.alpha = 0.8; 
    } else { 
     self.alpha = 1.0; 
    } 
    [super setHighlighted:highlighted]; 
} 
4

Jeśli dzwonisz reloadData gdy użytkownik przeciągając pogląd, że może być powodem.

Miałem awarie związane z tym z podobnymi raportami o awariach i "naprawiono" problem przez opóźnienie wywołania reloadData, aż użytkownik zakończy przewijanie widoku. Na przykład. stwórz zapakowaną metodę zamiast bezpośrednio wywoływać reloadData.

- (void)updateData { 
    if (self.collectionView.isTracking) { 
     self.updateDataOnScrollingEnded = YES; 
    } else { 
     [self.collectionView reloadData]; 
    } 
} 

Następnie, gdy przewijanie się kończy, wywołaj metodę updateData (jeśli jest taka potrzeba) z metod delegatów widoku przewijania.

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate 
{ 
    if (!decelerate) { 
     [self scrollViewStopped:scrollView]; 
    } 
} 

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 
{ 
    [self scrollViewStopped:scrollView]; 
} 

- (void)scrollViewStopped:(UIScrollView *)scrollView 
{ 
    if (self.updateDataOnScrollingEnded) { 
     [self updateData]; 
     self.updateDataOnScrollingEnded = NO; 
    } 
} 

Domyślam się, że jest słaby odniesienie do indexPath podświetlonej komórki gdzieś wewnątrz CollectionView, a nazywając reload będzie dealloc że indexPath. Gdy collectionView spróbuje odświeżyć komórkę, ulega awarii.

EDIT:

Jak wspomniano w komentarzach poniżej, to "rozwiązanie" ma pewne wady. Podczas dalszego badania problemu wydaje się, że w moim przypadku problem dotyczył wielokrotnych wywołań reloadData, które były kolejkowane w wątku głównym podczas przeciągania widoku kolekcji. Gdy było tylko jedno wywołanie reloadData, wszystko było w porządku, ale gdy było więcej niż jedno - awarie!

Od zawsze miałem dokładnie jeden punkt w moim CollectionView Wymieniłem połączenia reloadData z

reloadSections:[NSIndexSet indexSetWithIndex:0] 

to jednak powoduje, że komórki do szybkiego zanikania i ponownego których unikałem z następującym sposobem (IT będzie prawdopodobnie lepiej jako kategoria w widoku kolekcji)

- (void)reloadCollectionView:(UICollectionView *)collectionView animated:(BOOL)animated 
{ 
    [UIView setAnimationsEnabled:animated]; 
    [collectionView performBatchUpdates:^{ 
     [collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; 
    } completion:^(BOOL finished) { 
     [UIView setAnimationsEnabled:YES]; 
    }]; 
} 

jak dotąd, to działa dobrze dla mnie, a także pozwala na dane faktycznie być aktualizowane podczas przewijania.

+0

Myślę, że to nęka problem ... kiedy zacznie się śledzić widok kolekcji, podświetli komórkę, ale gdy zostanie wywołane polecenie reloadData, wygląda na to, że podświetlony status zostanie zachowany nawet po zatrzymaniu śledzenia. W tym momencie, kiedyś w przyszłości, stara podświetlona ścieżka indeksu spowoduje awarię. Niestety dla twojego rozwiązania, śledzenie może się uruchamiać i zatrzymywać bez ciągłego uruchamiania, co oznacza, że ​​nigdy nie otrzymasz żadnych wywołań zwrotnych do wywoływania reloadData (a ponieważ początek przeciągania zwykle un-podświetla komórki, prawdopodobnie nie jest to problemem, gdy isDragging jest TAK). –

+0

Kolejna sprawa, o której należy pamiętać; upewnij się, że wszystkie metody delegatów i źródła danych są przygotowane do akceptowania NSIndexPaths odnoszących się do starych danych do momentu wywołania -reloadData. Te z pewnością można wywołać podczas przeciągania i przewijania, a bez opcji -reloadData widok kolekcji nadal opiera swoje wywołania na poprzednich danych. –

+0

Dobre punkty! Odkąd napisałem odpowiedź, odkryłem, że wywoływanie reloadData na kolekcjiView po raz drugi (zanim miała szansę przeładować dane po raz pierwszy) wydawało się być prawdziwym problemem. Metoda reloadSections nie miała tego problemu, a ponieważ opracowana przeze mnie aplikacja zawsze miała jedną sekcję z co najmniej jedną komórką, zamiast tego przełączyłem się na reloadSections. – toostn

1

Miałem ten problem, chociaż nieco inna awaria. Naprawiono przez zatrzymanie wszelkich ponownych załadowań, dopóki nie zostanie wyczyszczone podświetlenie. Podczas gdy sugestia toostna rozwiązałaby problem, przydaje się możliwość ponownego ładowania danych podczas przewijania, ale nie ma większego sensu podczas podświetlania - gdy masz palec na komórce.

wdrożyć następujące metody UICollectionViewDelegate:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath { 
    self.allowReload = NO; 
    return YES; 
} 


- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath { 
    self.allowReload = YES; 
    [self reloadIfNecessary]; // calls reloadData if it is necessary to do so! 
} 
+0

Myślę, że ta odpowiedź jest bliżej źródła problemu. Sprawdziłem, czy jeśli NIE zwrócę NO z shouldHighlight, to nie otrzymam już awarii. Nadal nie wiem dokładnie, gdzie jest reloadData, ale jest tak, jakby były niefiltrowane połączenia odłożone przed rozpoczęciem dotykania i jeśli zadzwonię do reloadData między czasem rozpoczęcia i zakończenia światła, I jeśli przewijam wystarczająco szybko, takie że komórka jest poza ekranem (i prawdopodobnie dealloc'd?), wtedy dostaję tę katastrofę. Wielkie dzięki za podpowiedź! – tyler

+0

Edytuj: Mów za szybko. Dziwne, nadal dostaję crash wyskakujący z unhighlight nawet jeśli zwrócę NO z shouldHighlight ... Również, odraczając ponowne ładowanie do po didUnhighlightItem wynika w tym samym wyjątku. – tyler

0

miałem również ten Zawieszenie w _unhighlightAllItems w widoku zbiórki, gdzie użyłem rozpoznawania długie naciśnięcie, który zmienia stan komórki (ale nie ich liczba), a następnie zwanych [collectionView reloadData]. W moim przypadku rozwiązanie z @toostn (przy użyciu performBatchUpdates) działa świetnie.

Odkryłem również, że używanie reloadItemsAtIndexPaths: zamiast reloadData pozwala również uniknąć awarii.