2013-06-05 27 views
17

Tôi hơi bị mắc kẹt với điều này ... bất kỳ trợ giúp nào đều được đánh giá cao. Tôi đã dành rất nhiều thời gian để sửa lỗi này.Hiệu suất kém UITableViewCell với AutoLayout

Tôi có UITableView với nguồn dữ liệu được cung cấp bởi NSFetchedResultsController. Trong một bộ điều khiển xem riêng biệt, tôi chèn bản ghi mới vào CoreData bằng cách sử dụng [NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:], lưu ngữ cảnh đối tượng được quản lý và loại bỏ bộ điều khiển đó. Công cụ rất chuẩn.

Những thay đổi trong bối cảnh đối tượng được quản lý sau đó được nhận bởi NSFetchedResultsController:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { 
     [self.tableView beginUpdates]; 
} 

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { 
     [self.tableView endUpdates]; 
} 

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { 
    switch (type) { 
     case NSFetchedResultsChangeInsert: 
      [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 

      break; 

     case NSFetchedResultsChangeDelete: 
      [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 

      break; 

     case NSFetchedResultsChangeUpdate: 
      [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 

      break; 

     case NSFetchedResultsChangeMove: 
      [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; 
      [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone]; 

      break; 
    } 
} 

Và đây là nơi mà các vấn đề xuất hiện - phải mất quá nhiều thời gian (khoảng 3-4 giây trên iPhone 4) để làm điều đó. Và có vẻ như thời gian được dành để tính toán bố cục cho các ô.

Tôi đã xóa mọi thứ khỏi ô (bao gồm cả lớp con tùy chỉnh) và để nó chỉ với UILabel, nhưng không có gì thay đổi. Sau đó, tôi đã thay đổi phong cách của ô thành Cơ bản (hoặc bất kỳ thứ gì ngoại trừ Tùy chỉnh) và sự cố đã biến mất - các ô mới được thêm ngay lập tức.

Tôi đã kiểm tra gấp đôi và NSFetchedResultsControllerDelegate gọi lại chỉ được gọi một lần. Nếu tôi bỏ qua chúng và làm [UITableView reloadSections:withRowAnimation:], không có gì thay đổi - nó vẫn còn rất chậm.

Dường như đối với tôi, Bố cục tự động bị vô hiệu hóa đối với kiểu ô mặc định, điều này khiến chúng rất nhanh. Nhưng nếu đó là trường hợp - tại sao mọi thứ tải nhanh chóng khi tôi đẩy UITableViewController?

Đây là dấu vết cuộc gọi cho vấn đề đó: stack trace

Vậy câu hỏi được - những gì đang xảy ra ở đây? Tại sao các tế bào được kết xuất chậm?

UPDATE 1

tôi đã xây dựng một ứng dụng demo rất đơn giản để minh họa vấn đề tôi gặp phải. đây là nguồn - https://github.com/antstorm/UITableViewCellPerformanceProblem

Hãy thử thêm ít nhất một màn hình ô để cảm nhận vấn đề về hiệu suất.

Cũng lưu ý rằng việc thêm hàng trực tiếp (nút "Chèn ngay bây giờ!") Không gây ra bất kỳ sự chậm trễ nào.

+2

Chỉ cần xác nhận - bạn đang chỉ định các ô tùy chỉnh của bạn một số nhận dạng duy nhất và khử chúng thay vì tạo lại, đúng không? – James

+0

và quy tắc bố cục tự động nào được chỉ định trên ô? – Wain

+0

Có, tôi đang chỉ định một số nhận dạng duy nhất và các ô khử de sử dụng '[UITableView dequeueReusableCellWithIdentifier: forIndexPath:]'. –

Trả lời

2

Ok, cuối cùng tôi đã giải quyết vấn đề này mà không làm mất hoạt ảnh. Giải pháp của tôi là thực hiện giao diện của UITableViewCell trong một tệp Nib riêng biệt với tính năng AutoLayout bị tắt. Phải mất một chút thời gian để tải và bạn cần tự định vị các bản xem phụ.

Dưới đây là đoạn code để làm cho nó có thể:

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    ...   

    UINib *rowCellNib = [UINib nibWithNibName:@"RowCell" bundle:nil]; 
    [self.tableView registerNib:rowCellNib forCellReuseIdentifier:@"ROW_CELL"]; 
} 

Tất nhiên bạn sẽ cần một tập tin RowCell.nib với quan điểm của di động của bạn.

Mặc dù không có giải pháp cho vấn đề ban đầu (rõ ràng là lỗi của tôi), tôi đang sử dụng lỗi này.

+0

Tôi không hiểu giải pháp này. Bố cục tự động có bị tắt hay không, bằng cách nào đó bạn có lừa hệ thống để đạt được hiệu suất không? –

+0

Bí quyết là có tệp Xib riêng biệt (với Bố cục Tự động bị vô hiệu hoá) cho mỗi ô. Bằng cách đó, giao diện tổng thể đã bật bố cục tự động, nhưng mỗi ô - không. –

+0

Nhưng mỗi lần, các tế bào không được nạp từ nib. Khung nhìn bảng dequeues tế bào tái sử dụng từ bộ nhớ, và chúng đã được nạp từ ngòi. Vì vậy, về cơ bản bạn đã tắt bố cục tự động trên các ô. Làm thế nào là một giải pháp cho vấn đề? –

16

Đúng là Bố cục tự động có thể trình bày một lần truy cập hiệu suất. Tuy nhiên, đối với hầu hết các trường hợp, nó không thực sự đáng chú ý. Có một số trường hợp cạnh với bố trí phức tạp, nơi loại bỏ nó sẽ tạo ra một sự khác biệt có ý nghĩa, nhưng đó không thực sự là vấn đề ở đây.

Tôi không có giải thích lý do tại sao ứng dụng hoạt động theo cách của nó, nhưng ít nhất tôi có giải pháp: Không cập nhật chế độ xem bảng nếu chế độ xem bảng không hiển thị trên màn hình. Điều này dẫn đến hành vi kỳ lạ này.

Để làm được điều này, bạn có thể, ví dụ: kiểm tra self.tableview.window != nil trong các phương thức ủy nhiệm của bộ điều khiển kết quả tìm nạp. Sau đó, bạn chỉ cần thêm [self.tableview reloadData] vào viewWillAppear để chế độ xem bảng cập nhật dữ liệu của nó trước khi xuất hiện trên màn hình.

Hy vọng điều đó sẽ hữu ích.Và xin vui lòng, nếu ai đó có một lời giải thích tốt cho hành vi kỳ lạ này, xin vui lòng cho tôi biết :)

+0

Có, '[UITableView reloadData]' thực sự giải quyết vấn đề, nhưng bạn sẽ không nhận được hình động và nó cần phải cấu hình lại tất cả các ô trên màn hình. Sử dụng '[UITableView reloadSections: withRowAnimation:]' có thể tải lại dữ liệu bảng với hoạt ảnh, nhưng chậm như phương thức gốc. –

+1

Điều này làm việc kỳ diệu, cảm ơn. Tôi đã mở rdar: // 15175803 cho vấn đề này. –

+1

Điều này giải quyết vấn đề tương tự của tôi quá. Tôi đã lưu ngữ cảnh đối tượng được quản lý trong 'viewWillAppear'. Việc chuyển sang 'viewDidAppear' đã giải quyết được vấn đề về hiệu suất: điều gì đó khiến bố cục chậm hơn nhiều nếu chế độ xem không hiển thị trên màn hình. –

0

Nếu bạn vẫn muốn sử dụng Bố cục tự động trong các ô xem bảng, có nhiều cách để làm cho nó hoạt động. Đó là một quy trình nhiều bước, nhưng một khi bạn làm như vậy, bạn có thể có công cụ Tự động sắp xếp xác định kích thước dọc của ô ngoài bố cục của mọi thứ khác trong ô.

Bạn có thể tìm thêm chi tiết ở đây: Using Auto Layout in UITableView for dynamic cell layouts & variable row heights trong đó bao gồm một số phím tắt mà bạn có thể thực hiện nếu bạn đang ở trên iOS 8.

0

Tôi có vấn đề tương tự với việc sử dụng một bố cục tự động phức tạp trong một lớp con UITableViewCell. Bố trí ô của tôi phụ thuộc vào dữ liệu đến từ máy chủ, nhưng số trạng thái ô được giới hạn là sáu. Vì vậy, mỗi khi tôi nhận được nil từ dequeueReusableCellWithIdentifier (một ô mới được tạo), tôi thiết lập một reuseIdentifier động/tùy chỉnh cho ô vừa tạo (self.dynamicReusableIdentifier). Các reuseIdentifier getter được ghi đè trong subclass UITableViewCell (ACellSubclass):

- (NSString*) reuseIdentifier { 

    return self.dynamicReusableIdentifier; 
} 

Thế hệ của chuỗi self.dynamicReusableIdentifier được dựa trên một phương pháp tĩnh (configureDynamicReuseIdentifier) ​​được định nghĩa trong lớp tế bào (ACellSubclass). tableView: cellForRowAtIndexPath sau đó chọn các định tái sử dụng đúng trở về từ các

cell = [tableView dequeueReusableCellWithIdentifier: [ACellSubclass configureDynamicReuseIdentifier: someData]];

và các bản xem trước tĩnh của ô được sử dụng lại (nhãn, hình ảnh) được cập nhật mà không có bất kỳ thay đổi bố cục tự động nào.

2

Tôi có performence cùng trong [bảng reloadData] trong iOS 7. Trong trường hợp của tôi, tôi giải quyết vấn đề này để thay thế mã di động cấu hình từ [cell layoutIfNeeded] vào mã sau:

[cell setNeedsUpdateConstraints]; 
[cell setNeedsLayout]; 

và sau đó trở lại tế bào. Evevthing có vẻ ok. Tôi hy vọng điều này có thể giúp những người khác có cùng một vấn đề.

+0

Làm việc cho tôi. Dễ dàng! Cảm ơn, –