2017-04-18 10 views
2

我在我的自定義單元格文件在tableview中有問題。我設法使用下面顯示的註釋行來完成它,但是當它有10多個單元時,性能非常糟糕。 UsingdequeueReusableCell導致這個錯誤:TableView CellReuse

「NSInternalInconsistencyException」,原因:「無法出列具有標識符DiveNewsShort細胞 - 必須註冊標識符的筆尖或一類或在一個情節串連圖板連接原型細胞」

這很奇怪,因爲我在viewDidLoad()中註冊了nib。我希望你能幫助我,我對此感到沮喪。

class ProfilTableView: UITableViewController { 

    override func viewDidLoad() { 

    super.viewDidLoad() 

    tableView.register(UINib(nibName: "DiveNewsShort", bundle: nil), forCellReuseIdentifier: "DiveNewsShort") 

    tableView.register(DiveNewsShort.self, forCellReuseIdentifier: "DiveNewsShort") 
    } 

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

    // let cell = Bundle.main.loadNibNamed("DiveNewsShort", owner: self, options: nil)?.first as! DiveNewsShort 
    // This one works as expected 

    let cell = tableView.dequeueReusableCell(withIdentifier: "DiveNewsShort", for: indexPath) as! DiveNewsShort 
    // This one does not 

return cell } 

StoryBoard Picture


更新:

我設法通過在cellForRowAt功能將寄存器功能擺脫錯誤的,但我不認爲這是一個有效的實際上。它應該在vieDidLoad內工作嗎?

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

    tableView.register(UINib(nibName: "DiveNewsShort", bundle: nil), forCellReuseIdentifier: "DiveNewsShort") 
    let cell = tableView.dequeueReusableCell(withIdentifier: "DiveNewsShort", for: indexPath) as! DiveNewsShort 

return cell } 
+0

你爲什麼要爲'tableView.register'對同一個標識符進行兩次調用? – rmaddy

+0

在NIB中設置基類,不註冊類,只註冊NIB。或者在故事板中使用單元格原型,並且根本不需要NIB,也不需要手動註冊任何內容。但是如果你在多個表中重用NIB,那麼註冊NIB是好方法(但顯然沒有任何單元原型)。 – Rob

+0

您是否在故事板中設置了單元格標識符? – mat

回答

1

有三種註冊單元用於重用/出列的方式:

  1. 您正在編程創建單元格,在這種情況下,您在viewDidLoad中註冊該類。

  2. 您正在使用NIB,在這種情況下,您在viewDidLoad中註冊了NIB。

  3. 您正在使用故事板細胞原型,在這種情況下,您不必註冊任何東西。故事板爲你做了所有這些。

由於您使用的是NIB,您應該刪除該類的註冊並僅註冊NIB。你應該在viewDidLoad中這樣做。該過程在https://stackoverflow.com/a/28490468/1271826以及Reinier's answer中概述。在your MCVE

看,你的問題是一個更爲根本的錯誤,在這裏你有一個UIViewController試圖用另一種視圖控制器,這是一個UITableViewController,管理表的結果。但是UITableViewController有它自己的UITableView,並且不會使用那個你有@IBOutlet的那個,所以你註冊了一個你沒有看到的表格視圖的NIB。這裏還有很多其他問題(例如,如果你真的想在視圖控制器中使用視圖控制器,則必須執行視圖控制器包含調用等),但最簡單的解決方案是從項目中刪除此單獨的UITableViewController,以及何時這是固定的,它正如我們所描述的那樣工作。有關您的MCVE的工作版本,請參閱https://github.com/robertmryan/Divers

您也未連接單元中其他兩個控件(開關和滑塊)的插座。因此,如果您更改了這兩個控件中的任意一個,然後滾動,那麼這些單元格將被重用,您會看到爲其他單元格完成的更改後的UIKit控件,但隨後被重用。爲了解決這個問題,您的定製UITableViewCell子類應該有所有控件的插座,並且cellForRowAt必須爲所有這些插座設置值。您還需要一些單元機制來通知視圖控制器何時更改開關和滑塊並相應地更新模型,因此當稍後調用該行時,它將知道該CellData的狀態以適當地設置控件。一個常見的解決方案是使用協議委託模式。看到上面的GitHub回購,也說明了這種模式。

+0

另外,你的MCVE中沒有任何東西表明你必須使用NIB。我可能會建議使用故事板電池原型。它保持故事板中定義的整個UI。 – Rob

+0

哇。非常感謝你Rob!我懷疑使用單獨的視圖控制器可能是一個錯誤的來源,但我目前不熟悉tableviews,我認爲分離將是一個好主意。發現它不是,或者我目前還不夠聰明:-) nib文件完全是bs atm,將會有更復雜的內容,並且稍後將用於不同的表格視圖。我只是把一些東西放在裏面進行調試,這就是爲什麼它沒有連接到代碼。再次感謝您的耐心和努力! – Zorro02

3

你不需要這行:

tableView.register(DiveNewsShort.self, forCellReuseIdentifier: "DiveNewsShort") 

您已經註冊過的考生筆尖文件中的一行。

+0

謝謝,刪除它,但它不工作atm – Zorro02

+0

@ Zorro02 - 您是否在您的NIB中設置了基類?我假設你沒有任何細胞原型?錯誤是否與以前一樣?編輯你的問題,提供更多的細節。 – Rob

+0

@Rob我沒有任何原型單元格。我如何在NIB中設置基類?你的意思是自定義班嗎? – Zorro02

0

我建立這個協議幫助我在這個過程中

protocol CBNibInstanceableCellProtocol { 
    static func getCellXib() -> UINib? 

    static func getReuseIdentifier() ->String 
} 

,並在你的類,你必須實現像這裏

//example implementation 
extension CBUsersAttendanceEmptyCell : CBNibInstanceableCellProtocol 
{ 
    static func getCellXib() -> UINib? 
    { 
     if Bundle.main.path(forResource: "CBUsersAttendanceEmptyCell", ofType: "nib") != nil 
     { 
      return UINib(nibName: "CBUsersAttendanceEmptyCell", bundle: nil) 
     } 
     return nil 
    } 

    static func getReuseIdentifier() ->String 
    { 
     return "CBUsersAttendanceEmptyCell" 
    } 
} 

然後在這些方法你viewDidLoad你必須這樣做這

//example code 
self.collectionView.register(CBUsersAttendanceAvatarCell.getCellXib(), forCellWithReuseIdentifier: CBUsersAttendanceAvatarCell.getReuseIdentifier()) 
self.collectionView.register(CBUsersAttendanceCountCell.getCellXib(), forCellWithReuseIdentifier: CBUsersAttendanceCountCell.getReuseIdentifier()) 
self.collectionView.register(CBUsersAttendanceEmptyCell.getCellXib(), forCellWithReuseIdentifier: CBUsersAttendanceEmptyCell.getReuseIdentifier()) 

在您的cellForRow

if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CBUsersAttendanceCountCell.getReuseIdentifier(), for: indexPath) as? CBUsersAttendanceCountCell 
     { 
      return cell 
     } 

您必須確定您在您的廈門國際銀行查看課程,這是非常重要的檢查這個圖片

enter image description here

enter image description here

希望這有助於