xcode 7 swift нашел nil, в то время как разворачивание необязательно в ячейке просмотра таблицы

79
8

Мне жаль, что я спрашиваю еще об одном "найденном nil unwrapping optional в TableViewCell", но после нескольких часов отладки и чтения других таких сообщений здесь я все еще застрял. Я думаю, что я покрыл все обычные ошибки, но все равно не могу заставить работать.

В качестве отправной точки все работает нормально, пока я использую метку по умолчанию в ячейке, на которую ссылается "cell.textLabel!.Text = mystring". И у меня есть другой случай, когда я настроил прототип ячейки с изображением и ярлыком, и это тоже сработало.

В текущем случае у меня есть обычный UIViewController, с некоторыми другими представлениями и встроенным UITableView. Обычный UIViewController устанавливается как делегат для ячеек.

Вот код SettingsCell.swift. Довольно просто. Маленькая точка слева от Outlet в xcode прочная, показывая, что розетка правильно подключена к ярлыку CellTwo на моей ячейке таблицы прототипов.

class SettingsCell: UITableViewCell {

@IBOutlet weak var CellTwo: UILabel!

override init(style: UITableViewCellStyle, reuseIdentifier reuseID: String?) {
super.init(style: style, reuseIdentifier: reuseID)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

В соответствующем диспетчере представлений SettingsVC.swift здесь находится код dequeueCell, который принимает нулевую ошибку при попытке установить значение cell.CellTwo.

Ячейки хорошо отображаются в представлении таблицы, но появляется только текстовый файл textLabel.txt по умолчанию, который является частью UILabel. Мой пользовательский ярлык вообще не отображается.

  func tableView(
tv: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

let cell = tv.dequeueReusableCellWithIdentifier("SettingsCell") as! SettingsCell
let row = indexPath.row

cell.textLabel!.text = SettingsNames[row]
// the commented out line below crashes on a nil unwrapped optional
// cell.CellTwo!.text = "Blah"
if let b = cell.CellTwo {
b.text = "Blah"
}
return cell
}

Благодаря небольшой опции "let b =", которая может быть отключена, приложение не разбивается, но моя вторая метка также не устанавливается. Наконец, рассмотрите вопрос о регистрации класса.

Многие примеры существуют в сети (без использования прототипов), где вы регистрируете класс, и я сделал это до успешного завершения. И я сделал пример, когда я создал собственную прототипную ячейку, и этот тоже отлично работал. Но... Я думаю, что все эти примеры использовали UITableViewController, а не обычный UIViewController + встроенный UITableView. Может быть, это имеет к этому какое-то отношение.

Во всяком случае, вот код init/viewDidLoad в UIViewController, который содержит UITableView. Как вы можете видеть из кода, UIViewController утверждает, что данные и делегирование обязанностей, и, конечно же, строки таблицы отображаются и работают нормально.

Я пробовал зарегистрироваться в обоих направлениях - без регистрации кода и с линией регистрации кода. Но это ничего не меняет - мой код по-прежнему падает на нулевую ссылку на мою пользовательскую метку в ячейке.

class SettingsVC: UIViewController, UITableViewDataSource, UITableViewDelegate {

override func viewDidLoad() {
super.viewDidLoad()
SettingsTV.dataSource = self
SettingsTV.delegate = self
// I tried with this line in and out, no difference, the crash still happens
//SettingsTV.registerClass(SettingsCell.self, forCellReuseIdentifier: "SettingsCell")
SettingsTV.estimatedRowHeight = 70
}

Он, как и мой пользовательский ярлык, не создается и не инициализируется каким-либо образом. Но я не могу это объяснить. Есть идеи? благодаря

спросил(а) 2021-01-19T22:47:52+03:00 9 месяцев, 1 неделя назад
1
Решение
91

Ответ на мою проблему был в инициализации SetCell, показанной в первом блоке выше. Эта последовательность инициализации была скопирована из примера, который работал нормально, но не использовал ИСТОРИЯ. Вместо этого этот пример ограничился использованием полей textLabel.text по умолчанию в определении UITableViewCell.

Чтобы решить эту проблему, я просто возвращался к своим примерам, пытаясь воссоздать проблему в примерах, которые уже работали. Вот ключ.

Если вы используете раскадровку с прототипом ячейки, инициализация ячейки таблицы не может выглядеть как первый блок в этой публикации !! Этот стиль работает только для ячеек без раскадровки.

Вместо этого он должен выглядеть следующим образом. Обратите внимание, что я прокомментировал код по умолчанию, который xcode вставляет в файл при его создании. Таким образом, вы можете иметь пустой класс для ячейки, если у вас есть места для Outlets.

        class SettingsCell: UITableViewCell {

@IBOutlet weak var XXXLabel: UILabel!
@IBOutlet weak var CellTwo: UILabel!

// override func awakeFromNib() {
// super.awakeFromNib()
// // Initialization code
// }
//
// override func setSelected(selected: Bool, animated: Bool) {
// super.setSelected(selected, animated: animated)
//
// // Configure the view for the selected state
// }
}

Вторая вещь, которая появилась, заключалась в том, что две метки на раскадровке были помещены в любой конец раскадровки любого размера. И мои ограничения помещают метку правой руки с края имитируемого устройства. Мне пришлось вращать устройство в симуляторе, и престо! был второй лейбл. Я должен использовать предварительный просмотр более регулярно. :-)

ответил(а) 2021-01-19T22:47:52+03:00 9 месяцев, 1 неделя назад
46

Другая часть ответа заключается в содержимом блока инициализации NSCoder, показанного в верхней части этого сообщения. Этот блок был скопирован из рабочего примера, который НЕ использовал ячейку прототипа раскадровки. Поэтому я часто принимал роковую ошибку, когда пытался это сделать с моей прототипной ячейкой tableview.

Вот как должен выглядеть этот блок (должен) выглядеть, если вы используете прототип ячейки. Требуемый NSCoder должен вызвать super.init, например:

      required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
//fatalError("init(coder:) has not been implemented")
}

Странно, что когда xcode автоматически исправляет проблему NSCoder, вставляя шаблон NSCoder, требуется init? функции, он вводит один, который будет разорвать с прототипом клеток. Почему бы не добавить строку super.init(..) вместо фатальной строки ошибки? Наверное, есть причина, но не тот, который я вижу.

Так или иначе, все это работает для меня сейчас, даже с представлением прототипа раскадровки. Поэтому я думаю, что все вопросы/проблемы решены для этого.

ответил(а) 2021-01-19T22:47:52+03:00 9 месяцев, 1 неделя назад
46

Пробовали ли вы определять свою настраиваемую ячейку в отдельном XIB вместо использования ячеек прототипа в представлении таблицы? Это почти то же самое, что и вы, но у него просто есть другой XIB файл из раскадровки. Чтобы создать XIB:

Файл → Новый файл → iOS → Пользовательский интерфейс → Пусто Перетащите UITableViewCell в XIB и настройте соответствующим образом. Установите свой класс в SettingsCell и подключите ярлыки и т.д. К вашему классу SettingsCell

Затем в вашем VC вы зарегистрируете его следующим образом:

 let nibName = UINib(nibName: "SettingsCell", bundle:nil)
self.SettingsTV.registerNib(nibName, forCellReuseIdentifier: "SettingsCell")

ответил(а) 2021-01-19T22:47:52+03:00 9 месяцев, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема