簡體   English   中英

dequeueReusableCellWithIdentifier:forIndexPath:VS dequeueReusableCellWithIdentifier:

[英]dequeueReusableCellWithIdentifier:forIndexPath: VS dequeueReusableCellWithIdentifier:

我已經閱讀了這個問題並且認為我理解了兩種方法之間的區別,直到找到一個奇怪的例子:

設置表格視圖單元格的樣式為基本 ,標識符為故事板中的單元格 ,代碼如下:

import UIKit

class TableViewController: UITableViewController {
    var items: [String]!

    override func viewDidLoad() {
        super.viewDidLoad()
        items = ["first", "second", "third"]
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        // either works fine
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell")! // let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)

        cell.textLabel?.text = items[indexPath.row]
        return cell
    }
}

在此輸入圖像描述

很簡單,但是當我將tableView:cellForRowAtIndexPath:方法分別更改為1,2,3,4個時:

情況1:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
    cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)

    cell.textLabel?.text = items[indexPath.row]
    return cell
}

案例2:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
    cell = tableView.dequeueReusableCellWithIdentifier("Cell")!

    cell.textLabel?.text = items[indexPath.row]
    return cell
}

案例3:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("Cell")!
    cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)

    cell.textLabel?.text = items[indexPath.row]
    return cell
}

案例4:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("Cell")!
    cell = tableView.dequeueReusableCellWithIdentifier("Cell")!

    cell.textLabel?.text = items[indexPath.row]
    return cell
}

案例1,2(不起作用):

在此輸入圖像描述

案例3,4(工作正常):

在此輸入圖像描述

如何解釋? 我認為從另一個角度理解這兩種方法確實很有幫助,任何意見都是受歡迎的。

在每種情況下,您為每行出列兩個單元格。 在情況1和2中,首先調用("Cell", forIndexPath: indexPath)版本。 在這種情況下,表格視圖以每行兩個單元格結束,一個完全重疊並遮擋另一個。 您可以在視圖檢查器中看到這個,因為您可以修改視角以查看后面:

在此輸入圖像描述

(我修改了cellForRowAtIndexPath代碼,如下所示:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCellWithIdentifier("plainCell", forIndexPath: indexPath)
    cell.textLabel!.text = "First cell for row \(indexPath.row)"
    cell = tableView.dequeueReusableCellWithIdentifier("plainCell", forIndexPath: indexPath)
    cell.textLabel!.text = "Second cell for row \(indexPath.row)"
    print("Cell being returned is \(cell)")
    return cell
}

為每個單元格指定不同的文本標簽。)在情況3和4中,首先調用("Cell")版本,表視圖每行只有一個單元格。

為什么不同的行為? 如果您創建UITableViewCell的自定義子類並在故事板中使用它,則可以覆蓋各種方法並添加print()語句以查看正在發生的事情。 特別是awakeFromNibdidMoveToSuperViewdeinit 發生的情況是,在情況1和2中,創建了第一個單元格(awakeFromNib)並立即將其添加(didMoveToSuperView)到superview,可能是表視圖或其子視圖之一。 在情況3和4中,創建了第一個單元格但未添加到超級視圖中。 相反,一段時間后,細胞被解除分配(deinit)。

(注意,如果第二個單元格使用("Cell", forIndexPath: indexPath)版本出列,它也會立即添加到("Cell", forIndexPath: indexPath) 。但是,如果第二個單元格使用("Cell")版本出列,則它是僅cellForRowAtIndexPath方法返回后才添加到cellForRowAtIndexPath 。)

因此,關鍵的區別在於("Cell", forIndexPath: indexPath)版本導致單元格被立即添加到表視圖中,甚至在cellForRowAtIndexPath完成之前。 這在您提到的問題/答案中暗示,因為它表明出列單元格的大小正確。

一旦添加到superview,第一個單元格就不能被釋放,因為它的superview仍然有一個強引用。 如果單元格以("Cell")版本出列,則它們不會被添加到超級視圖中,因此一旦重新分配cell變量,就沒有對它們的強引用,因此它們被解除分配。

希望這一切都有意義。

dequeueReusableCellWithIdentifier:不保證:單元格可能nil ,因此您必須檢查您的單元格是否nil並正確處理它或您的應用程序將崩潰。

dequeueReusableCellWithIdentifier:forIndexPath:另一方面,它會為您檢查(它總是返回一個單元格)。

對於您的特定情況(Swift),這意味着您可以使用dequeueReusableCellWithIdentifier:forIndexPath:安全地強制解包單元格,而您必須使用if let語法和第二個。

示例代碼 (在Objective-C中,我不使用Swift)

dequeueReusableCellWithIdentifier:forIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" atIndexPath:indexPath];

    // Here we know the cell is not nil (....atIndexPath: ensures it)
    cell.textLabel.text = items[indexPath.row];

    return cell;
}

dequeueReusableCellWithIdentifier:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    // You asked for a cell, but you don't know if it is nil or not
    // In Swift, here the cell should be a conditional

    // First, check if the cell is nil
    if ( cell == nil ) {
        // Cell is nil. To avoid crashes, we instantiate an actual cell
        // With Swift conditional should be something similar
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    }

    // Here you're sure the cell is not nil
    // If condicional, you probably will write cell?.textLabel?.text = items[indexPath.row];
    cell.textLabel.text = items[indexPath.row];

    // Finally, you return the cell which you're 100% sure it's not nil
    return cell;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM