2009-12-10 12 views
5

Mam kilka dość skomplikowanych reguł dotyczących przesuwania wierszy wokół w UITableView. Istnieje nieokreślona liczba sekcji i wierszy na sekcję i na podstawie różnych reguł, wiersze mogą być przenoszone w obrębie sekcji lub między sekcjami przez użytkownika do określonych innych lokalizacji.Zawieszenie podczas próby przeniesienia UITableView wiersze

Wszystkie aktualizacje danych i wszystko działa. Ale od czasu do czasu, po przeniesieniu rzędu, aplikacja będzie się pomijać i nagle pojawi się puste miejsce, w którym powinien zostać wyświetlony wiersz.

Używam:

   - (NSIndexPath *)tableView:(UITableView *)tableView 
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath 

aby określić, gdzie użytkownik może przeciągnąć wiersze oparte na którym komórka jest. 98% czasu działania. Ale w niektórych przypadkach, gdy użytkownik może przeciągać tylko między sekcjami (nie można zmienić kolejności wierszy w sekcji) ten błąd pojawia się, a następnie aplikacja ulega awarii po przewinięciu obszaru bez wiersza.

Wyjątek wyrzucany jest bezużyteczny:

zakończenie aplikacji ze względu nieprzechwyconego wyjątku 'NSRangeException', przyczyny: „*** - [NSCFArray objectAtIndex:]: wskaźnik (6) poza granicami (6)

Żaden z moich kodów nie jest na stosie. Ostatnia metoda jest specyficzne UITableView

-[UITableView(UITableViewInternal) _visibleCellForGlobalRow:]

Czy ktoś widział ten problem występuje wcześniej? Jakieś pomysły?

+0

Czy kiedykolwiek rozwiązać ten Ed? Nie ma poprawnej odpowiedzi i widzę te same problemy. – coneybeare

+0

Nie, nigdy nie rozwiązałem tego problemu. Musiałem rozluźnić reguły dotyczące miejsca, do którego można przeciągnąć wiersz, aby go nie było. –

+0

Czy wykonujesz jakąkolwiek operację ponownego ładowania (taką jak reloadData, reloadSections lub reloadRowsAtIndexPath) w swojej metodzie moveRowAtIndexPath? Miałem ten sam rodzaj problemu i próbowałem wykonać przeładowanie w opóźnionym performSelektorze, jak sugeruje Tom S. poniżej, i wydawało się, że działa, z wyjątkiem tego, że opóźniłem o 1 sekundę, aby utrzymać iPhone'a 3.x, 4 .x i symulator szczęśliwy. Dla pewności jest trochę hackish. –

Odpowiedz

0

Nie odwiedziłem tego problemu od jakiegoś czasu. Rozwiązaniem, które wymyśliłem, było usunięcie skomplikowanych reguł. Nie wiem, dlaczego zezwolili na użycie skomplikowanych reguł, jeśli aplikacja uległa awarii podczas korzystania z nich. Nie wiem, czy jest to poprawione w najnowszej wersji systemu operacyjnego, czy nie.

1

Wygląda na to, że coś jest żądane elementu 6 z tablicy, która zawiera tylko elementy w indeksach 0-5 (co oznacza 6 elementów).

Dzieje się tak zwykle, gdy kod próbuje zrobić:

NSUInteger index = [somearray count]; 
id obj = [somearray objectAtIndex:index]; 

ponieważ górna granica jest count i tablice rozpocząć od 0 ostatni element jest count - 1.

To może nie być bezpośrednio w kodzie, ale możesz ograniczać coś do wielu elementów, a następnie poprosić o jeden za ostatnim elementem.

+0

Należy zauważyć, że należy używać 'NSUInteger' dla wyniku' count', aby nie było ono przycięte (szczególnie podczas przenoszenia kodu do komputera Mac, gdzie 'NSUInteger' jest coraz częściej większe niż' int'). Ważne jest również, aby zachować go w postaci niepodpisanej, aby porównania z tą nigdy nie negatywną wartością zawsze miały sens. –

+0

To prawda, po prostu byłem leniwy ... – stefanB

+0

Jestem świadomy problemu podstawowego, ale ten kod, który uzyskuje dostęp do tablicy jest głęboko w ramach. Tak jak powiedziałem, w momencie katastrofy nie ma absolutnie żadnego kodu na stosie. U jego podstawy wygląda to jak błąd w obiekcie UITableView. –

1

Miałem podobny błąd z usunięciem, którego nie mogłem zrozumieć przez chwilę - ale wstawiłem [tableView beginUpdates] i [tableView endUpdates] wokół kodu i naprawiłem wszystko. Możliwe, że twoje źródło danych po prostu nie aktualizuje się, zanim spróbuje przerysować, i te metody powinny temu zapobiec (w każdym razie warto spróbować).

+0

Już wykonane, faktycznie. –

1

Czy aktualizacją modelu danych do tabeli w targetIndexPathForMoveFromRowAtIndexPath

lub w metodzie DataSource Delegat: tableView:moveRowAtIndexPath:toIndexPath:?

Zrobione z tabeli programowania View Przewodnik dla iPhone OS, pod komórkach tabeli zamianom:

Widok tabeli wysyła tableView: moveRowAtIndexPath: toIndexPath: do źródła danych (jeżeli realizuje się metoda).W tej metodzie źródło danych aktualizuje tablicę modeli danych , która jest źródłem elementów dla widoku tabeli , przenosząc element do innej lokalizacji w macierzy z innej lokalizacji w macierzy.

A dla metody delegata, jest napisane:

każdym razem, gdy przeciągany wiersz jest ponad przeznaczenia, widok tabeli wysyła tableView: targetIndexPathForMoveFromRowAtIndexPath: toProposedIndexPath: do swojego delegata (jeśli implementuje metodę ). W tej metodzie delegat może odrzucić bieżące miejsce docelowe dla przeciągniętego wiersza i określić alternatywny jeden z nich.

tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: jest do ustalenia, czy przeniesienie jest dozwolone, ale rzeczywiste zmiany w modelu danych powinno odbywać się w tableView:moveRowAtIndexPath:toIndexPath:

Być może to jest to, co robisz, ale nie mogę powiedzieć tylko od informacje, które podałeś.

+0

Nie, aktualizuję go w metodzie moveRowAtIndexPath –

2

Właśnie trafiłem w to, co uważam za ten sam problem w mojej aplikacji.

Sytuacja jest taka, że ​​mam dwie sekcje tabeli. Elementy można przeciągać w obrębie sekcji i między nimi. Użytkownicy mogą przeciągać komórki do dowolnego wiersza w pierwszej sekcji, ale w drugiej sekcji elementy są sortowane, więc dla dowolnej komórki istnieje tylko jeden prawidłowy wiersz.

Jeśli przewińę widok tak, aby dolna część sekcji 1 i górna część sekcji 2 była widoczna, weź element w sekcji 1, który sortuje u dołu sekcji 2, i przeciągnij go do górnej części sekcji 2 , moja metoda tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: zostaje wywołana i zwracam poprawną pozycję docelową, która znajduje się kilka wierszy poniżej dolnej części ekranu. W interfejsie użytkownika można wyświetlić pustą komórkę u dołu ekranu, która nie jest właściwym rzędem docelowym.

Kiedy puścisz komórkę, ta fałszywa komórka, która została utworzona u dołu ekranu (w środku sekcji 2), pozostanie tam! tableView:cellForRowAtIndexPath: nigdy nie zostanie do tego wezwany. Jak tylko spróbujesz zrobić cokolwiek z tą komórką, ulegasz awarii.

Moje pierwsze rozwiązanie polegało na wywołaniu [tableView reloadData] pod koniec tableView:moveRowAtIndexPath:toIndexPath:. Ale to powoduje awarię, więc zamiast tego nazywam to pośrednio po opóźnieniu. Ale jest jeszcze jeden błąd: po opóźnionym reloadData, tableView:moveRowAtIndexPath:toIndexPath: zostaje ponownie wywołany z fałszywym żądaniem, aby przenieść element znajdujący się jeden za końcem pierwszej sekcji do tej samej pozycji. Musiałem więc dodać kod, aby zignorować fałszywe prośby bez zgody operatora.

Tak więc, oto kod:

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)pathSrc toIndexPath:(NSIndexPath *)pathDst 
{ 
    // APPLE_BUG: after doing the delayed table reload (see below), we get a bogus 
    // request to move a nonexistant cell to its current location 
    if (pathSrc.row == pathDst.row && pathSrc.section == pathDst.section) 
    return; 

    // update your data model to reflect the move... 

    // APPLE_BUG: if you move a cell to a row that's off-screen (because the destination 
    // has been modified), the bogus cell gets created and eventually will cause a crash 
    [self performSelector:@selector(delayedReloadData:) withObject:tableView afterDelay:0]; 
} 

- (void)delayedReloadData:(UITableView *)tableView 
{ 
    Assert(tableView == self.tableView); 
    [tableView reloadData]; 
} 

Zauważ, że wciąż jest bug UI. Na ekranie przeciągnięta komórka zostaje ożywiona w pustą komórkę. Pod koniec animacji pusta komórka zostaje przerysowana z poprawnymi danymi dla tego wiersza, ale obserwujący ją użytkownik zauważy, że przeciągnięta komórka zostaje animowana w niewłaściwym miejscu, a następnie natychmiast przekształca się w inną komórkę.

To zdecydowanie głupkowaty interfejs użytkownika.Zastanawiałem się nad przewinięciem odpowiedniego wiersza docelowego na ekran, ale gdybym miał to zrobić, wypełniłbym ekran sekcją drugą, a wtedy każda próba cofnięcia się do pierwszej sekcji byłaby ciągle udaremniana przez moją (teraz denerwującą) autoskopię. Być może będę musiał zmienić interfejs użytkownika, ale wymagałoby to pewnych skomplikowanych i uciążliwych zmian w moim modelu danych.

+0

Cieszę się, że przynajmniej jedna inna osoba ma takie samo doświadczenie jak ja! –

0

Po prostu jestem świadkiem tego problemu. Jednak moja wersja awarii występuje na urządzeniu z systemem iOS 3.0, które próbuję obsługiwać, a mam tylko dwa wiersze w tabeli, które próbuję zmienić. Uruchomiłem aplikację z tym samym kodem na innym urządzeniu z iOS 4.0 i ten błąd został naprawiony.

Nadal badam to, ale od tej pory wyłączam przenoszenie wierszy na urządzeniach z iOS 3.0, dopóki nie zostanie znaleziona poprawka.

1

Tutaj Cityarray jest tablicą ...

id obj =[Cityarray objectatindex:sourceindexpath.row]; 
     [Cityarray removeObjectatindex:(sourceindexpath.row)]; 
     [Cityarray insertObject:obj atindex:destinationindexpath.row]; 
Powiązane problemy