Tableviews "cellForRowAt" никогда не вызывается после добавления реальных данных

Моя программа построена следующим образом:

У меня есть UIViewControllerSingleEventViewController для размещения и обработки данных события. Одним из его элементов является UIViewTeilnehmerTableView с UITableViewучастникиTableView в нем.

Как следует из названия, он предназначен для отображения пользователей, участвующих в мероприятии. Сначала я реализовал это без «реальных» данных. Я жестко запрограммировал массив пользователей и построил на его основе табличное представление. Это сработало отлично.

Но поскольку я реализовал метод fetchUsers и заполнил массив этой информацией, tableView вообще не появляется. Очевидно, что он ничего не отображает, когда я впервые загружаю страницу, потому что numberOfRowsInSection возвращает 0. Но даже после выборки, когда я перезагружаю табличное представление, а numberOfRowsInSection возвращает значение, табличное представление пусто. Во время отладки я заметил, что метод заполнения ячеек cellForRowAt никогда не вызывается. Я понятия не имею, что происходит, поскольку до использования реальных данных все работало.

Кто-нибудь может сказать мне, что происходит?

import UIKit
import Firebase

class TeilnehmerTableView: UIView, UITableViewDelegate, UITableViewDataSource {

var parentVC: SingleEventViewController?
var users = [User]()

let participantsTableView: UITableView = {
    let ctv = UITableView()
    return ctv
}()

override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.green
    setupTableView()
    setupViews()
    confBounds()
    fetchUsers()
}

func setupTableView() {
    participantsTableView.delegate = self
    participantsTableView.dataSource = self
    participantsTableView.register(TeilnehmerTVCell.self, forCellReuseIdentifier: TeilnehmerTVCell.reuseIdentifier)
    participantsTableView.tintColor = .white
}

func setupViews() {
    addSubview(participantsTableView)
}

func confBounds(){
    participantsTableView.anchor(top: topAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print("Users: ",users.count)
    return users.count
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    print("heightForRowAt Called")
    return 44
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    print("cellForRowAt Called")
    let row = tableView.dequeueReusableCell(withIdentifier: TeilnehmerTVCell.reuseIdentifier, for: indexPath) as! TeilnehmerTVCell
    row.user = users[indexPath.item]
    return row
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: false)
}

//MARK: - Methods
func fetchUsers() {
    print("Fetching users..")

    let ref = Database.database().reference().child("users")
    ref.observeSingleEvent(of: .value, with: { (snapshot) in
        guard let dictionaries = snapshot.value as? [String: Any] else { return }

        dictionaries.forEach({ (key, value) in

            if key == Auth.auth().currentUser?.uid {
                print("Found myself, omit from list")
                return
            }

            guard let userDictionary = value as? [String: Any] else { return }

            let user = User(uid: key, dictionary: userDictionary)
            self.users.append(user)
        })

        self.users.sort(by: { (u1, u2) -> Bool in
            return u1.username.compare(u2.username) == .orderedAscending
        })
        DispatchQueue.main.async( execute: {
            self.participantsTableView.reloadData()
        })


    }) { (err) in
        print("Failed to fetch users for search:", err)
    }
}

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

Это код для родительского SingleEventVC:

import UIKit
import MapKit

class SingleEventViewController: UIViewController {

var thisEvent: Event
var eventName: String?
var eventDescription: String?
var eventLocation: CLLocationCoordinate2D?
var eventStartingDate: Date?
var eventFinishingDate: Date?
var eventNeedsApplication: Bool?

let padding: CGFloat = 20

//MARK: - GUI Objects
let scrollView: UIScrollView = {
    let view = UIScrollView()
    return view
}()

let teilnehmerLabel: UILabel = {
    let label = UILabel()
    label.font = UIFont.systemFont(ofSize: 20)
    label.text = "Teilnehmer"
    label.textColor = .black
    return label
}()

let teilnehmerTV: TeilnehmerTableView = {
    let tvt = TeilnehmerTableView()
    tvt.backgroundColor = .brown
    return tvt
}()

let buttonDividerView: UIView = {
    let tdv = UIView()
    tdv.backgroundColor = UIColor.gray
    return tdv
}()

let participateButton: UIButton = {
    let button = UIButton()
    button.backgroundColor = CalendarSettings.Colors.buttonBG
    button.setTitle("Teilnehmen", for: .normal)
    button.setTitleColor(CalendarSettings.Colors.darkRed, for: .normal)
    return button
}()

init(event: Event) {
    thisEvent = event
    super.init(nibName: nil, bundle: nil)
    setupDefaultValues()
}

override func viewDidLoad() {
    super.viewDidLoad()
    applyDefaultValues()
    setupNavBar()
    setupViews()
    confBounds()
    getSnapshotForLocation()
}


//MARK: - Setup
func setupDefaultValues() {
    eventName = thisEvent.eventName
    eventDescription = thisEvent.eventDescription
    eventLocation = thisEvent.eventLocation
    eventStartingDate = thisEvent.eventStartingDate
    eventFinishingDate = thisEvent.eventFinishingDate
    eventNeedsApplication = thisEvent.eventNeedsApplication
}

func applyDefaultValues() {
    titleLabel.text = eventName
    descLabel.text = eventDescription
    if let start = eventStartingDate, let finish = eventFinishingDate {
        timeLabel.text = "Von \(start.getHourAndMinuteAsStringFromDate()) bis \(finish.getHourAndMinuteAsStringFromDate())"
    }

    if let location = eventLocation {
        locationLabel.text = getStringFromLocation(location: location)
        mapLabel.text = getStringFromLocation(location: location)
    }
    if let date = eventStartingDate {
        dateLabel.text = formatDate(date: date)
    }
}

func setupNavBar() {
    self.navigationItem.title = "Event"
}

func setupViews() {
    view.addSubview(scrollView)
    view.addSubview(participateButton)
    participateButton.addTarget(self, action: #selector (buttonClick), for: .touchUpInside)
    view.addSubview(buttonDividerView)

    scrollView.addSubview(teilnehmerLabel)
    scrollView.addSubview(teilnehmerTV)
    teilnehmerTV.parentVC = self
}

func confBounds(){
    let tabbarHeight = self.tabBarController?.tabBar.frame.height ?? 0
    let tableviewHeight: CGFloat = CGFloat(teilnehmerTV.users.count) * 44

    participateButton.anchor(top: nil, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: tabbarHeight, paddingRight: 0, width: 0, height: 50)
    buttonDividerView.anchor(top: nil, left: view.leftAnchor, bottom: participateButton.topAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0.5)

    scrollView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: buttonDividerView.topAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)



    teilnehmerLabel.anchor(top: descLabel.bottomAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: 20, paddingLeft: padding, paddingBottom: 0, paddingRight: padding, width: 0, height: 0)
    teilnehmerTV.anchor(top: teilnehmerLabel.bottomAnchor, left: view.leftAnchor, bottom: scrollView.bottomAnchor, right: view.rightAnchor, paddingTop: 5, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: tableviewHeight)
}

override func viewDidLayoutSubviews() {
    let objHeight = titleLabel.frame.height + locationLabel.frame.height + dateLabel.frame.height + timeLabel.frame.height + mapView.frame.height + notizenLabel.frame.height + descLabel.frame.height + teilnehmerLabel.frame.height + teilnehmerTV.frame.height
    let paddingHeight = 10+0+50+padding+20+5 - 15
    print(objHeight, paddingHeight)

    scrollView.contentSize = CGSize(width: view.frame.width, height: objHeight+paddingHeight)
}

//MARK: - Methods
@objc func buttonClick() {
    teilnehmerTV.participantsTableView.reloadData()
    print(teilnehmerTV.participantsTableView.numberOfRows(inSection: 0))
    scrollView.reloadInputViews()
}

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

да, в методе setupTableView.

Noodledew 13.09.2018 14:59

Добавьте код того, как вы будете использовать TeilnehmerTableView

Hitesh Surani 13.09.2018 15:02

Не допускается изменение имени методов Datasource и Delegate. Если я заменю tableview своим именем, он будет жаловаться на несоответствие протоколу. Код добавлен сейчас.

Noodledew 13.09.2018 15:10
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это потому, что вы не добавили TeilnehmerTableView в представление в SingleEventViewController, когда делаете запрос на выборку - вы делаете запрос во время инициализации TeilnehmerTableView. Попробуйте вызвать fetchUsers из SingleEventViewControllerпосле, вы добавили TeilnehmerTableView в представление; тогда он должен работать.

Ты мой мужчина! Пришлось также изменить ограничения tableviews, но теперь это работает. Спасибо!

Noodledew 13.09.2018 16:04

Другие вопросы по теме