Home > Blockchain >  How to create a Movie Table View?
How to create a Movie Table View?

Time:11-15

I am very very new to Swift programming and I am growing to dislike it very much. I am not grasping it aa easily as other languages.

I have a project I am working on and I cannot figure out what is wrong or why its isn't working.

In one view, I have a table view that has a cell. I am using an array to store all the values that I want to be stored in the corresponding elements in the table view.

When the user clicks on an individual cell in the table view, it will bring them to another view displaying other elements of the movie (runtime, image, director and year).

I have a template that I am using to code this and I think I have done everything correctly, but when I run the app, nothing shows.

I just want the table cells to show on startup, when I run the app. I can even troubleshoot myself if I can just have the table cells show.

Since I am so new to this language and XCode, I am having trouble navigating the IDE to find my issues. On top of much I am already struggling with Swift.

I could really use the help, if possible!

Here is all the code I have done:

    import UIKit

    class ViewController: UIViewController,
    UITableViewDelegate,
    UITableViewDataSource  {
    
    let movieList = ["Step Brothers", "Pulp Fiction", "Ali", "Harry Potter"]
    let yearList = ["2008", "1994", "2001", "2001"]
    let images = ["step_brothers", "pulp_fiction", "ali", "harry_potter3"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return movieList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let tempCell: TableViewCell = tableView.dequeueReusableCell(withIdentifier:         
                 "cell") as! TableViewCell
        
        tempCell.movieTitleLabel.text = movieList[indexPath.row]
        tempCell.movieYearLabel.text = yearList[indexPath.row]
        tempCell.movieImage.image = UIImage(named: images[indexPath.row]   ".jpeg")
        
        return tempCell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        let detailVC:MovieDetailViewController = self.storyboard?.instantiateViewController(withIdentifier: "MovieDetailViewController") as! MovieDetailViewController
       // assign the values to the local variable declared in ProductDetailViewController Class
        detailVC.movieImage = UIImage(named: images[indexPath.row]   ".jpeg")!
      
        // make it navigate to ProductDetailViewController
        self.navigationController?.pushViewController(detailVC, animated: true)
     }  
    }

This is for the individual cell in the table view:

import UIKit

class TableViewCell: UITableViewCell {

@IBOutlet weak var movieTitleLabel: UILabel!

@IBOutlet weak var movieYearLabel: UILabel!

@IBOutlet weak var movieImage: UIImageView!


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
 }
}

This is the MovieDetailViewController:

class MovieDetailViewController: UIViewController {

    @IBOutlet weak var movieDetailImage: UIImageView!
    
    @IBOutlet weak var runtimeLabel: UILabel!
    
    @IBOutlet weak var yearDetailLabel: UILabel!
    
    @IBOutlet weak var directorDetailLabel: UILabel!
    
    var runtime: String!  // holds the product name
    var year: String!  // holds the price
    var movieImage: UIImage! // holds the product image
    var director: String!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        movieDetailImage.image = movieImage
        runtimeLabel.text = runtime
        yearDetailLabel.text = year
        directorDetailLabel.text = director

        // Do any additional setup after loading the view.
    }
    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */
   }

This is the error shown in the terminal, but there are no actual errors in the code:

2022-11-14 17:39:28.232645-0500 Exercise01[25678:1217794] [Storyboard] Unable to find method -[(null) TableViewCell] 2022-11-14 17:39:28.259975-0500 Exercise01[25678:1217794] [Assert] UINavigationBar decoded as unlocked for UINavigationController, or navigationBar delegate set up incorrectly. Inconsistent configuration may cause problems. navigationController=<UINavigationController: 0x141012400>, navigationBar=<UINavigationBar: 0x142106160; frame = (0 47; 0 50); opaque = NO; autoresize = W; layer = <CALayer: 0x600001d72280>> delegate=0x141012400

I can throw in the AppDelegate and SceneDelegate if you need it, just let me know.

Thank you everyone, again! I greatly appreciate the help!

CodePudding user response:

I'd first recommend to get rid of Storyboards, they're error prone and debugging is a hell.

Your problem: I don't see you connecting the UITableView to the ViewController (with an IBOutlet if you use storyboards). What you need to do is setting the UITableViewDelegate and the UITableViewDataSource for that UITableView

class ViewController: UIViewController,
UITableViewDelegate,
UITableViewDataSource  {

let movieList = ["Step Brothers", "Pulp Fiction", "Ali", "Harry Potter"]
let yearList = ["2008", "1994", "2001", "2001"]
let images = ["step_brothers", "pulp_fiction", "ali", "harry_potter3"]

@IBOutlet weak var tableView: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()
    
    tableView.delegate = self
    tableView.dataSource = self
}

CodePudding user response:

I think that the delegate and datasource aren't the only errors... This is an example (complete code) for how you can do it programmatically:

class YourViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

let movieList = ["Step Brothers", "Pulp Fiction", "Ali", "Harry Potter"]
    let yearList = ["2008", "1994", "2001", "2001"]
    let images = ["step_brothers", "pulp_fiction", "ali", "harry_potter3"]

let tableView = UITableView() // declare tableView

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        tableView.backgroundColor = .white
        tableView.translatesAutoresizingMaskIntoConstraints = false // disable defaults constrints
        // set delegate and datasource
        tableView.delegate = self
        tableView.dataSource = self
        tableView.register(TableViewCell.self, forCellReuseIdentifier: "cell") // register your cell
        
        view.addSubview(tableView)
        tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
        tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return movieList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let tempCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell // get cellId and indexPath
        tempCell.movieTitleLabel.text = movieList[indexPath.row]
        tempCell.movieYearLabel.text = yearList[indexPath.row]
        tempCell.movieImage.image = UIImage(named: images[indexPath.row])
        
        return tempCell
    }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 80 // height of single row
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let cell = tableView.cellForRow(at: indexPath) as! TableViewCell // This is your cell in didSelectRow to obtain objects in there
    
    let detailVC = MovieDetailViewController()
    
    detailVC.movieImage = cell.movieImage.image ?? UIImage()
    detailVC.runtimeLabel.text = cell.movieTitleLabel.text
    detailVC.yearDetailLabel.text = cell.movieYearLabel.text
    
    navigationController?.pushViewController(detailVC, animated: true)
 }
}

this is your cell:

class TableViewCell: UITableViewCell {

let movieTitleLabel = UILabel()
let movieYearLabel = UILabel()
let movieImage = UIImageView()

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    contentView.backgroundColor = .white
    
    movieTitleLabel.textColor = .black
    movieYearLabel.textColor = .black
    
    movieTitleLabel.translatesAutoresizingMaskIntoConstraints = false
    movieYearLabel.translatesAutoresizingMaskIntoConstraints = false
    movieImage.translatesAutoresizingMaskIntoConstraints = false
               
    contentView.addSubview(movieImage)
    movieImage.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
    movieImage.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
    movieImage.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
    movieImage.widthAnchor.constraint(equalTo: contentView.heightAnchor).isActive = true
    
    let stackView = UIStackView(arrangedSubviews: [movieTitleLabel, movieYearLabel])
    stackView.axis = .vertical
    stackView.distribution = .fillEqually
    stackView.translatesAutoresizingMaskIntoConstraints = false
    
    contentView.addSubview(stackView)
    stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).isActive = true
    stackView.leadingAnchor.constraint(equalTo: movieImage.trailingAnchor, constant: 10).isActive = true
    stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10).isActive = true
    stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10).isActive = true
}

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

this is your movieDetailController:

class MovieDetailViewController: UIViewController {

let movieDetailImage = UIImageView()
let runtimeLabel = UILabel()
let yearDetailLabel = UILabel()

let runtime = String()  // holds the product name
var year = String()  // holds the price
var movieImage = UIImage() // holds the product image

override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .white
    movieDetailImage.translatesAutoresizingMaskIntoConstraints = false
    runtimeLabel.translatesAutoresizingMaskIntoConstraints = false
    yearDetailLabel.translatesAutoresizingMaskIntoConstraints = false
    
    movieDetailImage.image = movieImage
    movieDetailImage.contentMode = .scaleAspectFill
    
    runtimeLabel.textColor = .black
    runtimeLabel.textAlignment = .center
    yearDetailLabel.textColor = .black
    yearDetailLabel.textAlignment = .center
    
    view.addSubview(movieDetailImage)
    movieDetailImage.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    movieDetailImage.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    movieDetailImage.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    movieDetailImage.heightAnchor.constraint(equalTo: movieDetailImage.widthAnchor).isActive = true
    
    let stackView = UIStackView(arrangedSubviews: [runtimeLabel, yearDetailLabel])
    stackView.axis = .vertical
    stackView.distribution = .fillEqually
    stackView.translatesAutoresizingMaskIntoConstraints = false
    
    view.addSubview(stackView)
    stackView.topAnchor.constraint(equalTo: movieDetailImage.bottomAnchor).isActive = true
    stackView.leadingAnchor.constraint(equalTo: movieDetailImage.leadingAnchor).isActive = true
    stackView.heightAnchor.constraint(equalToConstant: 60).isActive = true
    stackView.trailingAnchor.constraint(equalTo: movieDetailImage.trailingAnchor).isActive = true
 }
}

And This is the result (there isn't any array for directorDetailLabel)

enter image description here

CodePudding user response:

I have tried your code, and I didn't get any errors, I hope you have set the data source and delegate of table view. Just add this to your viewDidLoad()

override func viewDidLoad() {
super.viewDidLoad()

  tableView.delegate = self
  tableView.dataSource = self
}
  • Related