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.
Czy kiedykolwiek rozwiązać ten Ed? Nie ma poprawnej odpowiedzi i widzę te same problemy. – coneybeare
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. –
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. –