![](/img/trans.png)
[英]When to use dequeueReusableCellWithIdentifier vs dequeueReusableCellWithIdentifier : forIndexPath
[英]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()
語句以查看正在發生的事情。 特別是awakeFromNib
, didMoveToSuperView
和deinit
。 發生的情況是,在情況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.