2013-05-07 29 views
5

Đi bắt đầu bằng cách nói rằng tôi đã nhìn thấy những câu hỏi này:iOS: tế bào cellForRowAtIndexPath đang nhận được lẫn lộn

iOS: UITableView mixes up data when scrolling too fast

(custom) UITableViewCell's mixing up after scrolling

Items mixed up after scrolling in UITableView

Việc đầu tiên và cuối cùng có vẻ rất phù hợp cho vấn đề của tôi, tuy nhiên tôi khá chắc chắn rằng tôi có logic cho mỗi phần để xác định những gì sẽ xuất hiện trong các tế bào (dữ liệu), nhưng họ vẫn bị lẫn lộn.

Sau đây là mã có liên quan:

- (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; 

}

thông tin có liên quan ở đây:

1) ClosestRenter là KHÔNG nil ... nó tồn tại. Vì vậy, mệnh đề else không bao giờ được thực hiện ... và đó là trường hợp.

2) Trong mã:

[self setupCellsWithClosestRenterCell:cell atIndexPath:indexPath]; 

Có một đơn giản:

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) Có 2 phần tại mọi thời điểm.

Vấn đề là phần 0 (phần đầu tiên) sẽ không có gì hơn chuỗi giữ chỗ đó. Phần 1 phải chứa các bản xem phụ tùy chỉnh của tôi (trong các ô mà nó thực hiện).

Mục 0 ban đầu chỉ có chuỗi giữ chỗ, tuy nhiên khi tôi cuộn xuống (và phần không còn hiển thị) và cuộn lên (nhanh) đôi khi có một ô dường như ngẫu nhiên từ phần 1 trong đó ... cái quái gì vậy? Làm sao? Tôi miễn cưỡng đổ lỗi cho việc tái sử dụng tế bào nhưng vào thời điểm này bên ngoài một cái gì đó thực sự ngớ ngẩn tôi không biết nó là gì.

Phần đáng lo ngại ở đây là ô trong phần 0 (chỉ có 1 hàng ở đó) không có phụ đề. Nhưng khi tôi di chuyển lên và xuống nhanh nó nhận được một (từ phần 1 rõ ràng) và sau đó tôi nhận được thông báo nhật ký "GÌ THE HECK" ...

Điều đáng nói đến là với vòng lặp for (một với những gì các thông điệp heck) không giải quyết vấn đề (vì nó loại bỏ các subviews không mong muốn) nhưng có phải là một cách tốt hơn. Bây giờ nó cảm thấy sai.

Bất kỳ ý tưởng nào?

(Hãy đánh dấu điều này là trùng lặp, nhưng tôi khá chắc chắn có điều gì đó khác đang diễn ra ở đây).

Cảm ơn.

Trả lời

4

Vì vậy, sau một chút thất vọng và phân tích cẩn thận, tôi đã tìm ra lý do tại sao các ô bị lẫn lộn.

Giả định của tôi về việc sử dụng lại ô (đặc biệt là với số nhận dạng) là vấn đề.

Trước đây tôi đã làm điều này:

static NSString *CellIdentifier = @"Cell"; 

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

Mà là tuyệt vời và tất cả, tuy nhiên có một vấn đề quan trọng. Tất cả các tế bào về mặt kỹ thuật giống nhau bên dưới ... sau khi tất cả chúng được phân bổ (không phải nil) hệ thống không thể xác định ô nào sẽ tái sử dụng cho dù phần đó là gì. Điều này có nghĩa là bất kỳ ô nào có thể được lấy từ hàng đợi, với bất kỳ thứ gì trong đó, và bị kẹt ở bất cứ nơi nào (mặc dù kiểm tra của tôi để đảm bảo phần 1 đi vào phần 1 và phần 0 (người thuê giả) ở lại đó).

Giải pháp:

- (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; 

}

Như bạn có thể thấy, phần 0 sẽ được nhận dạng tế bào riêng của mình. Như sẽ phần 1. Kết quả là khi một tế bào được dequeued, nó sẽ kiểm tra phần nào indexPath hiện đang ở và lấy ô chính xác.

Ugh, vấn đề khó chịu như vậy nhưng bây giờ tất cả đều có ý nghĩa :)

+0

Làm tốt lắm Jordan! Điều này đã cứu tôi rất nhiều thất vọng. –

+1

NGỌT LAWD BABY CHÚA GIÊSU. +10000. – Kezzer

0

Có một số cách để giải quyết vấn đề tái sử dụng ô này (và đó là vấn đề), và cách bạn đang làm bây giờ là ok. Vấn đề là khi bạn cuộn xuống và sao lưu lại, ô được trả lại cho phần 0 có thể là ô đã được sử dụng trước đó cho phần 1, vì vậy nó sẽ có bất kỳ bản xem phụ nào bạn đặt trong đó.Một cách khác để xử lý việc này là tạo hai ô mẫu thử khác nhau trong bảng phân cảnh và trả về một ô có nhãn đơn giản cho phần 0 và trả về một ô còn lại, với bất kỳ phần bổ sung nào được thêm vào trong IB, cho phần 1. Bằng cách này, bạn sẽ luôn nhận đúng loại ô cho từng phần mà không phải xóa bất kỳ phần phụ nào - bạn chỉ cần điền lại ô đó với dữ liệu chính xác.

+0

Sử dụng các ô mẫu trong bảng phân cảnh có thể giúp ích trong vấn đề này, tuy nhiên dự án không sử dụng bảng phân cảnh (Tôi đang ở trong nhóm và có thể là vấn đề). Chỉ các tệp Xib. –

+0

@JordanJohns, bạn cũng có thể tạo các ô tùy chỉnh trong tệp xib. Trong trường hợp đó, bạn cần đăng ký tệp đó bằng phương thức UITableView registerNib: forCellReuseIdentifier :. Đăng ký từng ô bạn muốn sử dụng, thường là trong phương thức viewDidLoad của nguồn dữ liệu của bảng. – rdelmar

1

Thêm một vấn đề khác đã giải quyết được vấn đề của tôi. Nơi tôi đã lưu lại bất kỳ thay đổi nào đã được thực hiện cho ô.

if (! self.cell) { 

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

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

}