2012-11-01 12 views
81

Tôi đang cố gắng tìm ra cách đặt UITableViewCellStyle khi sử dụng các phương pháp mới trong iOS 6 cho UITableView.Đặt kiểu UITableViewCell khi sử dụng iOS 6 UITableView dequeueReusableCellWithIdentifier: forIndexPath:

Trước đây, khi tạo UITableViewCell Tôi sẽ thay đổi UITableViewCellStyle enum để tạo các loại ô mặc định khác nhau khi gọi initWithStyle: nhưng từ những gì tôi có thể thu thập, điều này không còn là trường hợp.

Các tài liệu Apple cho UITableView khẳng định:

Return Value: Một UITableViewCell đối tượng với các dạng tái sử dụng đi kèm. Phương thức này luôn trả về một ô hợp lệ.

Thảo luận: Vì lý do hiệu suất, một cái nhìn bảng của nguồn dữ liệu nói chung nên tái sử dụng đối tượng UITableViewCell khi nó gán các tế bào để hàng trong tableView của nó: cellForRowAtIndexPath: phương pháp. Chế độ xem bảng duy trì một hàng đợi hoặc danh sách các đối tượng UITableViewCell mà nguồn dữ liệu đã đánh dấu để sử dụng lại. Gọi phương thức này từ đối tượng nguồn dữ liệu của bạn khi được yêu cầu cung cấp một ô mới cho khung nhìn bảng. Phương pháp này dequeues một tế bào hiện có nếu một là có sẵn hoặc tạo ra một cái mới dựa trên lớp hoặc tập tin nib bạn đã đăng ký trước đó.

quan trọng: Bạn phải đăng ký một lớp học hoặc nib tập tin bằng cách sử dụng registerNib: forCellReuseIdentifier: hoặc registerClass: forCellReuseIdentifier: Phương pháp trước khi gọi phương pháp này.

Nếu bạn đăng ký một lớp cho số nhận dạng được chỉ định và một ô mới phải được tạo, phương thức này khởi tạo ô bằng cách gọi phương thức initWithStyle: reuseIdentifier: của nó. Đối với các ô dựa trên nib, phương thức này sẽ nạp đối tượng ô từ tệp nib được cung cấp. Nếu ô hiện có có sẵn để sử dụng lại, phương pháp này sẽ gọi phương thức prepareForReuse của ô thay thế.

Đây là cách của tôi mới cellForRowAtIndexPath trông sau khi thực hiện các phương pháp mới:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *cellIdentifier = @"cell_identifier"; 

    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellIdentifier]; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; 

    return cell; 
} 

Code tôi có cho đến nay hoạt động tốt nhưng luôn luôn trả về phong cách mặc định. Làm cách nào tôi có thể thay đổi điều này để tôi có thể tạo các ô với các kiểu khác như UITableViewCellStyleDefault, UITableViewCellStyleValue1, UITableViewCellStyleValue2UITableViewCellStyleSubtitle?

Tôi không muốn phân lớp UITableViewCell, tôi chỉ muốn thay đổi kiểu mặc định như tôi có thể làm trước iOS 6. Có vẻ kỳ quặc rằng Apple sẽ cung cấp các phương pháp nâng cao nhưng với tài liệu tối thiểu để hỗ trợ triển khai.

Có ai đã nắm vững điều này hoặc gặp sự cố tương tự không? Tôi đang đấu tranh để tìm bất kỳ thông tin hợp lý nào cả.

Trả lời

103

Tôi biết bạn đã nói bạn không muốn tạo lớp con, nhưng có vẻ như không thể tránh khỏi. Dựa trên mã lắp ráp trong khi thử nghiệm trong iOS 6.0 mô phỏng, UITableView tạo ra trường hợp mới của UITableViewCell (hoặc lớp con của nó) bằng cách thực hiện

[[<RegisteredClass> alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:<ReuseIdentifier>] 

Nói cách khác, phong cách gửi (UITableViewCellStyleDefault) dường như được mã hóa cứng.Để làm được việc này, bạn sẽ cần phải tạo một lớp con đó sẽ ghi đè initializer mặc định initWithStyle:reuseIdentifier: và vượt qua phong cách bạn muốn sử dụng:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 
{ 
    // ignore the style argument, use our own to override 
    self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier]; 
    if (self) { 
     // If you need any further customization 
    } 
    return self; 
} 

Ngoài ra, nó có thể là tốt hơn để gửi registerClass:forCellReuseIdentifier: trong viewDidLoad, thay vì làm việc đó mỗi khi một tế bào được yêu cầu:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    [self.tableView registerClass:<RegisteredClass> forCellReuseIdentifier:<ReuseIdentifier>]; 
} 
+4

Tôi đã bắt đầu thừa nhận rằng điều này sẽ thực sự là trường hợp. Nó không phải là một vấn đề lớn nhưng phải phân lớp 'UITableViewCell' để có được các kiểu mặc định khác là một nỗi đau vì nó chỉ tạo ra các tệp không cần thiết. Cảm ơn bạn đã bình luận và xác nhận những nghi ngờ của tôi. – CaptainRedmuff

+11

Đừng quên rằng thay vì phân lớp, bạn có thể sử dụng phương thức iOS5 cũ, vẫn còn hợp lệ.Bằng cách đó bạn có thể khởi tạo bất kỳ kiểu kiểu ô nào mà bạn muốn. Xem câu trả lời khác. – SpacyRicochet

60

dequeueReusableCellWithIdentifier không bị phản đối, do đó bạn không cần phải sử dụng mới dequeueReusableCellWithIdentifier:forIndexPath:.

Sử dụng cách mới cùng với phương thức đăng ký thích hợp (trong viewDidLoad) nếu bạn đang sử dụng lớp ô tùy chỉnh nhưng sử dụng cách cũ nếu bạn muốn sử dụng một trong các enums UITableViewCellStyle.

+1

Được thăng hạng để chỉ ra rằng bạn không * phải * sử dụng các phương pháp mới lạ mắt. Chỉ khi chúng phù hợp với mục đích của bạn hoặc nếu các lựa chọn thay thế không được chấp nhận. – SpacyRicochet

+0

Nếu bạn đặc biệt quan tâm, bạn có thể ghi đè lên 'dequeueReusableCellWithIdentifier: forIndexPath:' để cung cấp cho một số mã định danh xây dựng các ô theo cách cũ (và trả về chúng). Các số nhận dạng khác sẽ gọi siêu và trả lại số đó. Nó có thể có ý nghĩa để có một 'NSDictionary' của định danh để khối xây dựng cho loại định danh. – Benjohn

11

Bạn có thể tránh một lớp con không liên quan bằng công xây dựng giao diện kịch bản:

  1. Trong giao diện Storyboard, chọn các tế bào nguyên mẫu xem bảng di động (trên xem bảng)
  2. Trong Utilities xem, trong Thuộc tính thanh tra, điều chỉnh giá trị Phong cách
  3. (Tùy chọn) sửa đổi các giá trị khác như lựa chọn và phụ kiện

iOS mới 6.0 dequeueReusableCellWithIdentifier:forIndexPath: không sử dụng các giá trị đó khi phân bổ các ô mới và trả lại chúng. (Thử nghiệm trên bản biên dịch iOS 6.0 bằng Xcode 4.5.2)

6

Một cách khác để lưu một tệp là tạo Nib và sử dụng registerNib:forCellReuseIdentifier: thay thế.

Làm cho Nib dễ dàng: Tạo tệp .xib mới trong Trình tạo giao diện. Xóa chế độ xem mặc định. Thêm một đối tượng ô xem bảng. Sử dụng Thanh tra thuộc tính, thay đổi kiểu cho ô. (Ở đây bạn cũng có cơ hội để tùy chỉnh các tế bào tiếp tục bằng cách điều chỉnh các thuộc tính khác.)

Sau đó, trong viewDidLoad gọi phương thức một cái gì đó quan điểm điều khiển bảng của bạn như:

[self.tableView registerNib:[UINib nibWithNibName:@"StyleSubtitleTableCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:@"Cell"]; 
+0

initWithStyle: reuseIdentifier không được gọi. – thierryb

-5

Giải pháp của tôi cho điều này là để gọi initWithStyle: reuseIdentifier: sau Tôi đã nhận được nó bằng cách sử dụng [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath]. Xét cho cùng, init chỉ là một bộ chọn khác, và trình biên dịch không hạn chế gọi nó trên một đối tượng đã được khởi tạo. tuy nhiên nó sẽ phàn nàn về việc không sử dụng kết quả của gọi init, vì vậy tôi làm:

UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath]; 
cell = [cell initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellId"]; 

Tôi tưởng tượng này sẽ không làm việc trong Swift ...

+0

Điều này hoạt động tốt trong Swift. – faraquet99

+0

Imo giải pháp thanh lịch nhất. Hy vọng rằng ruột của initWithStyle không tái tạo lại mọi thứ. –

+2

Vâng, tôi đoán nếu bạn đang làm nó như thế này, bạn có thể thả các công cụ dequeuing hoàn toàn ... – stk

0

câu trả lời Bolot là đúng. Đơn giản và bạn không cần tạo bất kỳ tệp XIB nào.

Tôi chỉ muốn cập nhật câu trả lời của mình cho bất cứ ai đang làm nó bằng cách sử Swift thay vì Objective-C:

override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 
    super.init(style: .value1, reuseIdentifier: reuseIdentifier) 
} 

required init?(coder aDecoder: NSCoder) { 
    fatalError("init(coder:) has not been implemented") 
}