2013-05-07 10 views
5

zamiar zacząć od stwierdzenia, widziałem te pytania:iOS: Komórki cellForRowAtIndexPath są coraz pomieszane

iOS: UITableView mixes up data when scrolling too fast

(custom) UITableViewCell's mixing up after scrolling

Items mixed up after scrolling in UITableView

Pierwszy i ostatni wydaje się bardzo istotne na mój problem, jednak jestem dość pewny, że mam logikę dla każdej sekcji, aby ustalić, co powinno pojawić się w komórce (dane), a mimo to wciąż się mieszają.

Poniżej znajduje się odpowiedni kod:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
//Note: the if (cell == nil) thing is no longer required in iOS 6 
static NSString *CellIdentifier = @"Cell"; 

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
if (cell == nil) 
{ 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 
} 


if (closestRenter != nil) 
{ 
    NSLog(@"CLOSEST RENTER!"); 
    [self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; 
} 
else 
{ 
    NSLog(@"NO CLOSEST RENTER"); 
    [self setupCellsWithNoClosestRenterCell:cell atIndexPath:indexPath]; 
} 

if (indexPath.section == 0) 
{ 
    for (UIView *view in cell.contentView.subviews) 
    { 
     NSLog(@"WHAT THE HECK"); 
     [view removeFromSuperview]; 
    } 
} 

return cell; 

}

Stosowna informacji tutaj:

1) ClosestRenter NIE jest zerowa ... istnieje. Tak więc klauzula else nie powinna nigdy zostać wykonana ... i tak właśnie jest.

2) w kodzie:

[self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; 

Jest to prosta

if (indexPath.section == 0) 
{ 
    cell.textLabel.text = @"PLACE HOLDER"; 
} 
else 
{ 
    // Populate the cell with data. (creates a view (with controller etc) and loads it into the cell) 
} 

3) są 2 sekcje w każdym momencie.

Problem polega na tym, że sekcja 0 (pierwsza sekcja) nie powinna mieć nic poza łańcuchem zastępczym. Sekcja 1 powinna zawierać moje własne subviews (w komórkach, które robi).

Sekcja 0 początkowo ma tylko ciąg znaków zastępczych, jednak gdy przewińę w dół (i sekcja nie jest już widoczna) i przewijam do góry (szybko), czasami ma ona pozornie losową komórkę z sekcji 1 tam ... co do diabła? W jaki sposób? Niechętnie obwinia się o ponowne użycie komórki, ale w tym momencie poza czymś naprawdę głupim nie wiem, co to jest.

Niepokojąca część tutaj polega na tym, że komórka w sekcji 0 (tam jest tylko jeden rząd) nie ma subviews. Ale kiedy szybko przewijam w górę iw dół, otrzymuję jeden (z sekcji 1 widocznie), a następnie otrzymuję komunikaty dziennika "CO TO THE HECK" ...

Warto wspomnieć, że z pętlą for (tą z to, co komunikaty heck), rozwiązuje problem (ponieważ usuwa niepożądane subviews), ale musi być lepszy sposób. Czuje się źle teraz.

Wszelkie pomysły?

(Możesz oznaczyć to jako duplikat, ale jestem pewien, że dzieje się tu coś jeszcze).

Dzięki.

Odpowiedz

4

Po odrobinie frustracji i dokładnej analizie dowiedziałem się, dlaczego komórki się pomieszały.

Moje założenie dotyczące ponownego użycia komórki (szczególnie z identyfikatorami) było problemem.

Wcześniej robiłem to:

static NSString *CellIdentifier = @"Cell"; 

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
if (cell == nil) 
{ 
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 
} 

Który jest wielki i wszystko, jednak nie jest to krytyczny problem. Wszystkie komórki były pod tym samym względem technicznym ... po tym, jak wszystkie zostały przydzielone (nie zerowe), system nie mógł określić, która komórka zostanie użyta ponownie bez względu na to, jaką sekcję to było.

Oznaczało to, że jakakolwiek komórka mogła zostać wyrwana z kolejki, z czymkolwiek w niej została, i zatrzymana w dowolnym miejscu (pomimo moich czeków, aby upewnić się, że sekcja 1 poszła w sekcji 1 i sekcja 0 rzeczy (fałszywy najemca) zatrzymałem się tam).

Rozwiązanie:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
//Note: the if (cell == nil) thing is no longer required in iOS 6 
static NSString *CellIdentifier1 = @"Cell"; 
static NSString *CellIdentifier2 = @"Cell2"; 

UITableViewCell *cell; 

if (indexPath.section == 0) 
{ 
    if (cell == nil) 
    { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier1]; 
    } 
    else 
    { 
     cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1]; 
    } 

} 
else 
{ 
    if (cell == nil) 
    { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier1]; 
    } 
    else 
    { 
     cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2]; 
    } 
} 


if (closestRenter != nil) 
{ 
    NSLog(@"CLOSEST RENTER!"); 
    [self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; 
} 
else 
{ 
    NSLog(@"NO CLOSEST RENTER"); 
    [self setupCellsWithNoClosestRenterCell:cell atIndexPath:indexPath]; 
} 

return cell; 

}

Jak widać, sekcja 0 dostanie swój własny identyfikator komórki. Tak jak w sekcji 1. Rezultat jest taki, że gdy komórka ma zostać usunięta, sprawdza ona, w której sekcji jest aktualnie indeksowana ścieżka i pobiera odpowiednią komórkę.

Ugh, tak frustrujący problem, ale teraz to wszystko ma sens :)

+0

Dobra robota Jordan! To zaoszczędziło mi wiele frustracji. –

+1

SWEET LAWD BABY JEZUS. +10000. – Kezzer

0

Istnieje kilka sposobów radzenia sobie z tym problemem ponownego wykorzystania komórki (i na tym polega problem), a sposób, w jaki to robisz, jest w porządku. Problem polega na tym, że po przewinięciu w dół i utworzeniu kopii zapasowej komórka, która została zwrócona dla sekcji 0, może być komórką, która była poprzednio używana dla sekcji 1, więc będzie zawierała wszystkie subviews, które tam umieścisz.

Innym sposobem radzenia sobie z tym zadaniem jest utworzenie dwóch różnych prototypowych komórek w scenorysie i zwrócenie go za pomocą prostej etykiety dla sekcji 0 i zwrócenie drugiej z dodanymi w IB opiniami do sekcji 1. W ten sposób zawsze otrzymasz właściwy typ komórki dla każdej sekcji bez konieczności usuwania jakichkolwiek subskrybentów - wystarczy ponownie wypełnić komórkę odpowiednimi danymi.

+0

Korzystanie z prototypowych komórek w serii ujęć prawdopodobnie pomogłoby w tym zakresie, jednak projekt nie korzysta z storyboardów (jestem w zespole i może to być problem). Tylko pliki Xib. –

+0

@JordanJohns, możesz również tworzyć własne komórki w pliku XIB. W takim przypadku musisz zarejestrować ten plik przy użyciu metody UITableView registerNib: forCellReuseIdentifier :. Zarejestruj każdą komórkę, której chcesz użyć, zwykle w metodzie viewDidLoad źródła danych tabeli. – rdelmar

1

dodając jeszcze rozwiązać mój problem. Gdzie zresetowałem wszelkie zmiany wprowadzone w komórce.

if (! self.cell) { 

self.cell = [[LanguageCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 

self.cell.accessoryType = UITableViewCellAccessoryNone; 
} 
else { 
self.cell.checkImage.image = NO; 

} 
Powiązane problemy