Khi nào nên sử dụng dequeueReabilitiesCellWithIdentifier vs dequeueReabilitiesCellWithIdentifier: forIndexPath


167

Có hai tình trạng quá tải cho dequeueReabilitiesCellWithIdentifier và tôi đang cố gắng xác định khi nào tôi nên sử dụng cái này với cái kia?

Các tài liệu apple liên quan đến hàm forIndexPath, "Phương thức này sử dụng đường dẫn chỉ mục để thực hiện cấu hình bổ sung dựa trên vị trí của ô trong chế độ xem bảng."

Tôi không chắc làm thế nào để giải thích điều đó mặc dù?

Câu trả lời:


216

Sự khác biệt quan trọng nhất là forIndexPath:phiên bản khẳng định (sự cố) nếu bạn không đăng ký một lớp hoặc ngòi cho mã định danh. Phiên bản cũ hơn (không phải forIndexPath:) trả về niltrong trường hợp đó.

Bạn đăng ký một lớp cho một định danh bằng cách gửi registerClass:forCellReuseIdentifier:đến chế độ xem bảng. Bạn đăng ký một ngòi cho một định danh bằng cách gửi registerNib:forCellReuseIdentifier:đến chế độ xem bảng.

Nếu bạn tạo chế độ xem bảng và các nguyên mẫu ô của mình trong bảng phân cảnh, trình tải bảng phân cảnh sẽ đảm nhiệm việc đăng ký các nguyên mẫu ô mà bạn đã xác định trong bảng phân cảnh.

Phần 200 - Có gì mới trong Ca cao cảm ứng từ WWDC 2012 thảo luận về forIndexPath:phiên bản (sau đó mới) bắt đầu khoảng 8m30s. Nó nói rằng, bạn sẽ luôn nhận được một tế bào được khởi tạo (mà không đề cập đến việc nó sẽ bị sập nếu bạn không đăng ký một lớp hoặc ngòi).

Đoạn video cũng nói rằng, nó sẽ có kích thước phù hợp với đường dẫn chỉ số đó. Có lẽ điều này có nghĩa là nó sẽ đặt kích thước của ô trước khi trả lại, bằng cách nhìn vào chiều rộng của chế độ xem bảng và gọi tableView:heightForRowAtIndexPath:phương thức của đại biểu của bạn (nếu được xác định). Đây là lý do tại sao nó cần đường dẫn chỉ mục.


Điều đó thực sự hữu ích, cảm ơn. Có kích thước ô tại thời điểm dequeue dường như ít lợi thế hơn với các ràng buộc kích thước và bố cục tự động?
Stewohn

38

dequeueReusableCellWithIdentifier:forIndexPath:sẽ luôn trả lại một ô. Nó sẽ sử dụng lại các ô hiện có hoặc tạo một ô mới và trả về nếu không có ô nào.

Trong khi, truyền thống dequeueReusableCellWithIdentifier:sẽ trả về một ô nếu nó tồn tại tức là nếu có một ô có thể được sử dụng lại, nó sẽ trả về một ô khác. Vì vậy, bạn sẽ phải viết một điều kiện để kiểm tra nilgiá trị là tốt.

Để trả lời câu hỏi của bạn, hãy sử dụng dequeueReusableCellWithIdentifier:khi bạn muốn hỗ trợ iOS 5 và các phiên bản thấp hơn vì dequeueReusableCellWithIdentifier:forIndexPathchỉ có sẵn trên iOS 6+

Tham khảo: https://developer.apple.com/library/ios/documentation/uikit/reference/UITableView_Class/Reference/Reference.html#//apple_ref/occ/instm/UITableView/dequeueReusableCellWithIdentifier:forIndexPath :


Không, nó không phải lúc nào cũng trả về một ô 2014-12-26 07: 56: 39.947 testProg [4024: 42920390] *** Lỗi xác nhận trong - [UITableView dequeueReabilitiesCellWithIdentifier: for IndexPath:], /SourceCache/UIK UITableView.m: 6116 2014-12-26 07: 56: 39.954 Interphase [4024: 42920390] *** Chấm dứt ứng dụng do ngoại lệ chưa được ghi nhận hoặc một lớp cho mã định danh hoặc kết nối một ô nguyên mẫu trong bảng phân cảnh '
xóa sáng

@binarystar Bạn phải đăng ký một ngòi hoặc lớp của ô tùy chỉnh của bạn trong chế độ xem đã tải. như:[self.tableView registerNib:[UINib nibWithNibName:@"cell" bundle:nil] forCellReuseIdentifier:@"cell"];
GoodSp33d

6

Tôi chưa bao giờ hiểu lý do tại sao Apple tạo ra phương thức mới hơn, dequeueReabilitiesCellWithIdentifier: forIndexPath :. Tài liệu của họ về họ không đầy đủ, và có phần sai lệch. Sự khác biệt duy nhất tôi có thể nhận ra giữa hai phương thức, đó là phương thức cũ hơn có thể trả về con số không, nếu nó không tìm thấy một ô có mã định danh được truyền vào, trong khi phương thức mới hơn gặp sự cố, nếu nó không thể quay lại một tế bào. Cả hai phương thức đều được đảm bảo trả về một ô, nếu bạn đã đặt định danh chính xác và đặt ô trong bảng phân cảnh. Cả hai phương thức cũng được đảm bảo trả về một ô nếu bạn đăng ký một lớp hoặc xib và tạo ô của bạn bằng mã hoặc tệp xib.


3
Phương thức mới sử dụng đường dẫn chỉ mục để xác định kích thước phù hợp cho ô.
cướp mayoff

1
@robmayoff Nhưng điều này có ý nghĩa gì không? Nếu không có phương pháp mới, kích thước của ô vẫn có thể được đặt đúng. Phương pháp mới có thể cung cấp bất kỳ thuận tiện?
fujianjin6471

1
Đọc đoạn cuối câu trả lời của tôi để biết chi tiết.
cướp mayoff 29/07/2015

Vì vậy, điều này có nghĩa là, nếu tất cả các ô của tôi có cùng kích thước trong bảng, thì tôi không gọi là phương thức nào?
Happiehappie

2
Nếu tôi cung cấp tableView.estimateHeight, kích thước của ô cũng sẽ được xác định đúng. Tôi vẫn không nhận được lợi ích của phương pháp mới.
Ryan

1

Nói ngắn gọn:

dequeueReusableCell(withIdentifier, for)chỉ hoạt động với các tế bào nguyên mẫu. Nếu bạn đã cố sử dụng nó khi ô nguyên mẫu vắng mặt, nó sẽ làm hỏng ứng dụng.

Hollemans M. 2016, Danh sách kiểm tra Chương 2, Học viên iOS (Phiên bản thứ 5). Trang: 156.


-2

Tôi khuyên bạn nên sử dụng cả hai nếu bạn đang sử dụng nội dung được tạo động. Nếu không, ứng dụng của bạn có thể bị sập bất ngờ. Bạn có thể thực hiện chức năng của riêng mình để lấy một ô có thể tái sử dụng tùy chọn. Nếu đó là nilbạn nên trả về một ô trống không hiển thị:

Swift 3

// Extensions to UITableView
extension UITableView
{
    // returns nil, if identifier does not exist. 
    // Otherwise it returns a configured cell for the given index path
    open func tryDequeueReusableCell (
        withIdentifier identifier: String, 
        for indexPath: IndexPath) -> UITableViewCell?
    {
        let cell = self.dequeueReusableCell(withIdentifier: identifier)
        if cell != nil {
            return self.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
        }  
        return nil
    }
}

Và phần mở rộng để trả về một ô trống:

// Extension to UITableViewCell
extension UITableViewCell
{
    // Generates an empty table cell that is not visible
    class func empty() -> UITableViewCell
    {
        let emptyCell = UITableViewCell(frame:CGRect(x:0, y:0, width:0, height:0))
        emptyCell.backgroundColor = UIColor.clear
        return emptyCell
    }
}

Một ví dụ đầy đủ về cách sử dụng nó:

import Foundation
import UIKit

// A protocol is used to identify if we can configure
// a cell with CellData
protocol ConfigureAbleWithCellData
{
    func configure(_ data: CellData)
}

class MyCustomTableViewCell :
    UITableViewCell,
    ConfigureAbleWithCellData
{
    @IBOutlet weak var title:UILabel! = nil
    func configure(_ data: CellData)
    {
        self.title.text = data.title
    }
}

// This actually holds the data for one cell
struct CellData
{
    var title:String = ""
    var reusableId:String = ""
}

class CosmoConverterUnitTableViewController:
    UIViewController,
    UITableViewDelegate,
    UITableViewDataSource
{
    // Storage
    var data = Array<Array<CellData>>()

    func loadData()
    {
        var section1:[CellData] = []
        var section2:[CellData] = []

        section1.append(CellData(title:"Foo", reusableId:"cellType1"))
        section2.append(CellData(title:"Bar", reusableId:"cellType2"))

        data.append(section1)
        data.append(section2)
    }

    func tableView(_ tableView: UITableView,
                   numberOfRowsInSection section: Int) -> Int
    {
        return data[section].count
    }

    public func numberOfSections(in tableView: UITableView) -> Int
    {
        return data.count
    }

    func tableView(
        _ tableView: UITableView,
        cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        guard
            indexPath.row < data[indexPath.section].count
            else
        {
            fatalError("this can't be")
        }

        let cellData = data[indexPath.section][indexPath.row]

        if let cell = tableView.tryDequeueReusableCell(
            withIdentifier: cellData.reusableId,
            for: indexPath)
        {
            if let configurableCell = cell as? ConfigureAbleWithCellData
            {
                configurableCell.configure(cellData)
            }
            else
            {
                // cell is not of type ConfigureAbleWithCellData
                // so we cant configure it.
            }
            return cell
        }
        // id does not exist
        return UITableViewCell.empty()
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.