Reputation:
I want to pass the data from one controller to another controller when user click the button by using segue . I data is coming from UITableViewCell in bother cases . In first view the data is loaded successfully from API but when I clicked the button to show the details ,It is showing following error .. Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value.. on this line ... self.mc.movieTtile.text = dc.movieTitle.text!.. Although I mentioned that It will have the value with ! mark .
Here is the code for first view controller cell.
class MovieViewCell: UITableViewCell {
static let identifier = "MovieViewCell"
@IBOutlet weak var mainStackView: UIStackView!
@IBOutlet weak var movieImage: UIImageView!
@IBOutlet weak var movieTtile: UILabel!
@IBOutlet weak var movieOverview: UILabel!
func configureCell(title: String?, overview: String?, data: Data?) {
movieTtile.text = title
movieOverview.text = overview
if let imageData = data{
movieImage.image = UIImage(data: imageData)
}
}
}
Here is the code into view controller .
class NewViewController: UIViewController {
var mc : MovieViewCell!
var vc : ViewController!
var dc: DeatilsViewCell!
@IBOutlet weak var tableView: UITableView!
private var presenter: MoviePresenter!
@IBOutlet weak var name: UILabel!
var finalname = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
name.text = "Hello: " + finalname
setUpUI()
// configure presenter
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
@IBAction func showMovieDetails(_ sender: Any) {
self.mc.movieTtile.text = dc.movieTitle.text!
self.mc.movieOverview.text = dc.movieOverview.text!
self.mc.movieImage.image = dc.movieImage.image
// self.movieTitleDetail = mc.movieTtile.text!
//self.movieOverviewDeatil = mc.movieOverview.text!
//self.movieImageDetail = mc.movieImage.image
performSegue(withIdentifier: "details", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var vc = segue.destination as! DetailsViewController
dc.movieTitle.text = mc.movieTtile.text
dc.movieOverview.text = mc.movieOverview.text
dc.movieImage.image = mc.movieImage.image
/*vc.finalmovieTitle = self.movieTitleDetail
vc.finalmovieOverview = self.movieOverviewDeatil
vc.finalmovieImage = self.movieImageDetail*/
}
private func setUpUI() {
tableView.dataSource = self
tableView.delegate = self
}
@IBAction func change(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 1{
setUpUI()
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
}
}
extension NewViewController: MovieViewProtocol {
func resfreshTableView() {
tableView.reloadData()
}
func displayError(_ message: String) {
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
let doneButton = UIAlertAction(title: "Done", style: .default, handler: nil)
alert.addAction(doneButton)
present(alert, animated: true, completion: nil)
}
}
extension NewViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
presenter.rows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
}
extension NewViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
Here is the code for second UIViewController Cell.
class DeatilsViewCell: UITableViewCell {
static let identifier = "DeatilsViewCell"
@IBOutlet weak var movieImage: UIImageView!
@IBOutlet weak var movieTitle: UILabel!
@IBOutlet weak var movieOverview: UILabel!
}
Here is the Second view Controller code to display the values from first view controller .
class DetailsViewController: UIViewController {
var dc : DeatilsViewCell!
var mc : MovieViewCell!
@IBOutlet weak var tableView: UITableView!
/* var finalmovieTitle = ""
var finalmovieOverview = ""
var finalmovieImage: UIImage?*/
override func viewDidLoad() {
super.viewDidLoad()
dc.movieTitle.text = mc.movieTtile.text
dc.movieOverview.text = mc.movieOverview.text
dc.movieImage.image = mc.movieImage.image
}
}
Upvotes: -1
Views: 320
Reputation: 100541
Here
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var vc = segue.destination as! DetailsViewController
dc.movieTitle.text = mc.movieTtile.text
dc.movieOverview.text = mc.movieOverview.text
dc.movieImage.image = mc.movieImage.image
/*vc.finalmovieTitle = self.movieTitleDetail
vc.finalmovieOverview = self.movieOverviewDeatil
vc.finalmovieImage = self.movieImageDetail*/
}
You set dc
that's defined here var dc: DeatilsViewCell!
which for sure has nil outlets as it's not loaded with IB , BTW this is not the way to pass data to other vc , you need to create vars/model in destination vc
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! DetailsViewController
vc.finalmovieTitle = // string value please don't use mc
vc.finalmovieOverview = // string value please don't use mc
vc.finalmovieImage = // string value please don't use mc
}
Then inside DetailsViewController
var finalmovieTitle,finalmovieOverview,finalmovieImage = ""
Which should be used , also remove those
override func viewDidLoad() {
super.viewDidLoad()
dc.movieTitle.text = mc.movieTtile.text
dc.movieOverview.text = mc.movieOverview.text
dc.movieImage.image = mc.movieImage.image
}
From viewDidLoad
and implement table data source methods to assign the sent variables
Warning :- You shouldn't declare table Cells as variables inside a vc they are meant to be used inside cellForRowAt no where else
Upvotes: 0