Нил найден при распаковке необязательно - PullRequest
0 голосов
/ 03 декабря 2018

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

Структура

struct User {
    let name: String!
    let uid: String!
}

Ячейка табличного представления

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

    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

    // **** Crash is on the following line ****
    let nameTxtField = cell.viewWithTag(1) as! UILabel
    nameTxtField.text = users[indexPath.row].name
    return cell
}

Представление табличного представленияDidload

override func viewDidLoad() {
    super.viewDidLoad()
    let uid = Auth.auth().currentUser?.uid

    let ref: DatabaseReference! = Database.database().reference()

    ref.child("users").child(uid!).queryOrderedByKey().observe(.childAdded) { (snapshot) in
        let name = (snapshot.value as? NSDictionary)?["name"] as? String ?? ""

        let uid = (snapshot.value as? NSDictionary)?["uid"] as? String ?? ""

        self.users.append(User(name: name, uid: uid))

        self.tableView.reloadData()
    }

    tableView.reloadData()
}

Структура базы данных enter image description here

Ответы [ 3 ]

0 голосов
/ 03 декабря 2018

Согласно вашему комментарию вы получаете сбой на линии

let nameTxtField = cell.viewWithTag(1) as! UILabel

Это означает, что viewWithTag(1) либо возвращает nil, либо что-то отличное от UILabel.Либо вы не установили для тега метки значение 1, либо у вас есть несколько элементов пользовательского интерфейса с тегом 1 (viewWithTag вернет первое представление в иерархии с этим тегом).

Необходимо создатьсоответствующий UITableViewCell подкласс и свяжите ваш UILabel со свойством этого класса.Тогда вы можете сказать что-то вроде:

let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MyTableViewCell
cell.nameTxtField.text = users[indexPath.row].name

Пара других комментариев;Вы должны попытаться устранить как можно больше!насколько это возможно.

  • Свойства вашей структуры должны быть опциональными или неопциональными, а не неявно развернутыми опциональными.
struct User {
    let name: String
    let uid: String
}
  • Вы должны получить uid с оператором guard вместо принудительной распаковки позже
  • Ваш код для получения пользователя будет более понятным, если вы распределите его на несколько строк
  • Избегайте использования NS...объекты в Swift
  • Я также принимаю к сведению ответ Фрэнка относительно вашего доступа к Firebase, но я не знаю достаточно о Firebase, чтобы знать, является ли это проблемой или нет;

override func viewDidLoad() {
    super.viewDidLoad()
    guard let uid = Auth.auth().currentUser?.uid else {
        return
    }

    let ref: DatabaseReference! = Database.database().reference()

    ref.child("users").child(uid).queryOrderedByKey().observe(.childAdded) { (snapshot) in
        guard let result = snapshot.value as? [String:Any] else {
            return
        }

        let name = (result["name"] as? String) ?? ""

        let uid = (result["uid"] as? String) ?? ""

        self.users.append(User(name: name, uid: uid))

        self.tableView.reloadData()
    }

}
0 голосов
/ 03 декабря 2018

Кажется, что проблема в этой строке:

let nameTxtField = cell.viewWithTag(1) as! UILabel

Ячейка еще не загружена из раскадровки, поэтому cell.viewWithTag(1) равно нулю.Ноль +!= crash.

Обычно я заполняю ячейки следующим алгоритмом:

  1. Создаю отдельный класс для ячеек каждого типа
  2. Реализуем метод customizeUI() для заполнения необходимого пользовательского интерфейсаэлементы управления в ячейке
  3. Добавьте iVar типа данных, который будет отображаться в этой ячейке, и вызовите customizeUI () в его установщике.

    var item: HistoryItem?{didSet {customizeUI ()}}

Этот метод проверяет, загружена ли уже ячейка:

func customizeUI() {
    guard let label = self.nameLabel else {
        return
    }
    // Fill UI controlls
    label.text = item.name
    ...
}

Также этот метод должен вызываться в ячейках awakeFromNib()method.

И, наконец, в вашем методе cellAt... вы должны написать что-то вроде cell.item = dataItem вместо непосредственного заполнения элементов управления вашего пользовательского интерфейса.

0 голосов
/ 03 декабря 2018

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

Итак, вы выполняете прямое чтение, но используете queryOrderedByKey() и .childAdded.Это означает, что ваше закрытие вызывается с каждым дочерним элементом в /users/rPJSO..., один раз для каждого отдельного свойства: email, name, password, uid.И поскольку у name свойства в нет ни одного из них, поиск этого значения вернет nil.

Решение довольно простое: удалите queryOrderedByKey и прослушайте .value:

ref.child("users").child(uid!).observe(.value) { (snapshot) in
  ...

Остальной код может остаться прежним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...