Intereting Posts

TableView CellReuse

У меня проблемы с моим пользовательским файлом ячейки в tableview. Мне удалось сделать это, используя приведенную ниже строку комментария, но производительность была очень плохой, когда у нее было 10+ ячеек. UsingdequeueReusableCell приводит к этой ошибке:

«NSInternalInconsistencyException», причина: «неспособность деактивировать ячейку с идентификатором DiveNewsShort – должна зарегистрировать ниб или класс для идентификатора или подключить ячейку прототипа в раскадровке»,

что странно, потому что я регистрирую nib в viewDidLoad (). Надеюсь, вы можете мне помочь, меня это расстраивает.

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 Изображение


Обновить:

Мне удалось избавиться от ошибки, добавив функцию register в функцию 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 } 

Существует три способа регистрации ячеек для повторного использования / удаления:

  1. Вы программно создаете ячейки, и в этом случае вы регистрируете класс в viewDidLoad .

  2. Вы используете NIB, и в этом случае вы регистрируете NIB в viewDidLoad .

  3. Вы используете прототипы ячеек раскадровки, и в этом случае вам не нужно ничего регистрировать. Раскадровка делает все это для вас.

Поскольку вы используете NIB, вы должны удалить регистрацию класса и зарегистрировать только NIB. И вы должны сделать это в viewDidLoad . Этот процесс описан в https://stackoverflow.com/a/28490468/1271826, а также в ответе Рейнье .

Глядя на ваш MCVE , ваша проблема была результатом более фундаментальной ошибки, когда у вас был UIViewController пытающийся использовать другой контроллер представления, который был UITableViewController , для управления таблицей. Но UITableViewController имеет свой собственный UITableView и не будет использовать ту, для которой у вас есть @IBOutlet , поэтому вы регистрировали NIB для просмотра таблицы, которого вы не видели. Здесь было много других проблем (например, если вам действительно нужен контроллер вида в контроллере просмотра, вы должны делать вызовы сдерживания диспетчера вызовов и т. Д.), Но самым простым решением было исключить этот отдельный UITableViewController из проекта и когда это было исправлено, оно работает точно так, как мы описали. См. https://github.com/robertmryan/Divers для рабочей версии вашего MCVE.

Вы также не подключили розетки для двух других элементов управления в своей камере (переключатель и слайдер). Таким образом, если вы изменили один из этих двух элементов управления и затем прокручивались, ячейки повторно используются, и вы видите измененный элемент управления UIKit, который был сделан для какой-либо другой ячейки, но впоследствии был повторно использован. Чтобы исправить это, ваш пользовательский подкласс UITableViewCell должен иметь выходы для всех элементов управления, а cellForRowAt должен устанавливать значения для всех этих точек. Вам также нужен какой-то механизм для ячейки, чтобы информировать контроллер вида, когда переключатель и слайдер изменились, и соответственно обновили модель, поэтому, когда cellForRowAt позже был вызван для этой строки, он знал бы состояние этой CellData чтобы соответствующим образом настроить элемент управления. Общим решением для этого является использование шаблона делегирования протокола. См. Вышеупомянутое репо GitHub, которое также иллюстрирует этот шаблон.

Вам не нужна эта строка:

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

Вы уже зарегистрировали файл nib на одну строку раньше.

Я создал этот протокол, чтобы помочь мне в этом процессе

 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 } 

Вы должны определить класс для просмотра в своем xib, это очень важно проверить эти фотографии

введите описание изображения здесь

введите описание изображения здесь

Надеюсь это поможет