TableView being assigned to navigation controller not view controller

215 Views Asked by At

I have an app that is playing up. All my data is being displayed in the black circle. I need it to be displayed in the red circle. Is it a problem in my controller class or do I need to somehow assign the tableview to this controller? I couldn't find any solutions like this online

image1

This is my code for the ViewController class:

import UIKit
import SafariServices

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    private
    let tableView: UITableView = {
        let table = UITableView()
        table.register(NewsTableViewCell.self,
            forCellReuseIdentifier: NewsTableViewCell.identifier)
        return table
    }()

    private
    var viewModels = [NewsTableViewCellViewModel]()
    private
    var articles = [Article]()

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.hidesBackButton = true

        title = "News"
        view.addSubview(tableView)
        tableView.delegate = self
        tableView.dataSource = self
        // Do any additional setup after loading the view
        getTopArticles()
        searchArticles()
    }
    func getTopArticles() {
        ArticlesAPI.shared.getTopArticles {
            [weak self] result in //looking at API
                switch result {
                    case.success(let articles): // if there are results
                        self?.articles = articles
                    self?.viewModels = articles.compactMap({
                        NewsTableViewCellViewModel(title: $0.title, //tableview needs to be added
                            subtitle: $0.description ?? "No Description",
                            imageURL: URL(string: $0.urlToImage ?? ""))
                    })
                    // break
                    DispatchQueue.main.async {
                        self?.tableView.reloadData()
                    }
                    case.failure(let error): //prints error if there is one
                        print(error)
                }
        }

    }

    func searchArticles() {
        ArticlesAPI.shared.searchArticles(with: "apple") {
            [weak self] result in //looking at API
                switch result {
                    case.success(let articles): // if there are results
                        self?.viewModels = articles.compactMap({
                            NewsTableViewCellViewModel(title: $0.title, //tableview needs to be added
                                subtitle: $0.description ?? "No Description",
                                imageURL: URL(string: $0.urlToImage ?? ""))
                        })
                    //break
                    DispatchQueue.main.async {
                        self?.tableView.reloadData()
                    }
                    case.failure(let error): //prints error if there is one
                        print(error)
                }
        }

    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        tableView.frame = view.bounds
    }

    // table

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModels.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard
        let cell = tableView.dequeueReusableCell(withIdentifier: NewsTableViewCell.identifier,
            for: indexPath)
        as ? NewsTableViewCell
        else {
            fatalError()
        }
        cell.configure(with: viewModels[indexPath.row])
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let viewModel = viewModels[indexPath.row]

        let article = articles[indexPath.row]
        guard
        let url = URL(string: article.url ?? "")
        else {
            return
        }
        let vc = SFSafariViewController(url: url)
        present(vc, animated: true)
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 150
    }

}
1

There are 1 best solutions below

0
birkoof On

The red controller is embedded inside the black controller. The black controller is a navigation controller which provides the navigation bar for the red controller. You can type navigationController inside of your view controller and you will see that it is of type UINavigationController?, and Optional (?) since it may or may not exist (in your case it does exist because you embedded your controller in the storyboard). So don’t worry, your content is already inside the red view controller.

The reason why you think it isn’t, is because you have created your tableView programatically and you gave it the size of the whole screen, so it covers up all of the other content:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    tableView.frame = view.bounds
}

You can verify this using the layout inspector.

This isn’t needed because you already have a UITableView in your storyboard, you just need to create a reference to it in your view controller. So instead of:

private
let tableView: UITableView = {
    let table = UITableView()
    table.register(NewsTableViewCell.self, forCellReuseIdentifier: NewsTableViewCell.identifier)
    return table
}()

you need:

@IBOutlet private var tableView: UITableView!

and you can register your cell alongside the other tableView setup code inside the viewDidLoad method:

 // view.addSubview(tableView) -> autoLayout does this automatically, hence the name autoLayout
 tableView.register(NewsTableViewCell.self, forCellReuseIdentifier: NewsTableViewCell.identifier)
 tableView.delegate = self
 tableView.dataSource = self

And remove the code in your viewDidLayoutSubviews method as well, so that the tableView doesn’t take up all of the space.