I'm building a simple movie app by fetching some data from an API. My app navigation pattern looks like this: NavigationController as InitialViewController > TabBarController. TabBarController includes two ViewControllers: HomeViewController and FavouriteMoviesViewController. I have a button inside HomeViewController which pushes the SeachViewController page using navigation. I also have DetailsViewController. Whenever I press movie poster whether in HomeViewController or SearchViewController CollectionViewCell, it presents me DetailsPageViewController. I'm using delegation pattern(i set FavouriteMoviesViewController as a delegate of the DetailsViewController when I present DetailsViewController from HomeViewController) to update data inside FavouriteMoviesViewController from DetailsViewController, but the problem is that I can't set delegate when I access DetailsViewController from SearchViewController because these two ViewControllers are not related in any way. I tried to set an observer inside FavouriresViewController, but it won't work until I access that viewController
here's my code when i present DetailsViewController from HomeViewController and pass fetched data
// Cell action
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// Instantiate DetailsViewController and set it's delegate to FavouritesViewController to pass data
let targetVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: DetailsViewController.identifier) as! DetailsViewController
let favMoviesScreen = self.tabBarController?.viewControllers?[0] as! FavouritesViewController
targetVC.changeToFavouriteDelegate = favMoviesScreen
switch collectionView {
case self.trendingMoviesCollectionView:
let selectedMovie = trendingMovies[indexPath.row]
targetVC.movie = selectedMovie
targetVC.genreIDs = selectedMovie.genreIDs
self.navigationController?.present(targetVC, animated: true, completion: nil)
case self.upcomingMoviesCollectionView:
let selectedMovie = upcomingMovies[indexPath.row]
targetVC.movie = selectedMovie
targetVC.genreIDs = selectedMovie.genreIDs
self.navigationController?.present(targetVC, animated: true, completion: nil)
case self.topRatedMoviesCollectionView:
let selectedMovie = topRatedMovies[indexPath.row]
targetVC.movie = selectedMovie
targetVC.genreIDs = selectedMovie.genreIDs
self.navigationController?.present(targetVC, animated: true, completion: nil)
default: break
}
}
everything's good here.
here's DetailsViewController where i show movie details, i mark favourite movie here and add/remove it in my FavouriteMoviesViewController, this is delegate method:
// MARK: - Button Actions
@objc private func markAsFavourite() {
guard let favouriteMovie = movie else {
print("invalid movie object")
return
}
// check whether the movie is already added into favourite movies array
if !DetailsViewController.favouriteMovies.contains(where: { favouriteMovie.movieId == $0.movieId }) {
addToFavouritesButton.tintColor = .appRedColor
DetailsViewController.favouriteMovies.append(favouriteMovie)
changeToFavouriteDelegate?.addMovie(favouriteMovie)
} else {
addToFavouritesButton.tintColor = .white
DetailsViewController.favouriteMovies.removeAll(where: { $0.movieId == favouriteMovie.movieId})
changeToFavouriteDelegate?.removeMovie(favouriteMovie)
}
}
now the problem is here, in my SearchViewController,i guess because of the fact that this ViewController doesnt' belong to tabBar
// Cell action
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let targetVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: DetailsViewController.identifier) as! DetailsViewController
let tabBar = (self.navigationController?.viewControllers[0]) as! UITabBarController
let favMoviesController = tabBar.viewControllers![0] as! FavouritesViewController
targetVC.changeToFavouriteDelegate = favMoviesController
let selectedMovie = filteredMovies[indexPath.row]
targetVC.movie = selectedMovie
targetVC.genreIDs = selectedMovie.genreIDs
self.navigationController?.present(targetVC, animated: true, completion: nil)
}
this just doesn't work...
targetVC.changeToFavouriteDelegate = favMoviesController
Is there anything I can do to solve this problem?
CodePudding user response:
This might not answer your question completely however my intention is to point you in the right direction.
The issue could be one of several and it will be hard to debug without being able to run your code. Here are some possibilities:
- Your delegate could be set correctly but because the Favorites View is not on the screen, the UI updates are not executed and you do not do any reloading / refreshing when you go back there
- Maybe you are not accessing the desired instance of the Favorites ViewController
- One reason notifications would have not worked, maybe you aren't listening to it
- etc
It's hard to say easily.
In my opinion, the implementation to achieve what you want is quite complex.
I would recommend to simplify in the following ways:
- Simplest solution - Maintain a struct or a class of favorite movies which should be passed around between the classes
- One step further would be to look at MVVM as one of the commenters posted and using that with observers (Notifications) to update UI. I recommend checking this stanford lecture which I liked
- Might be an overkill at this stage but can read up on CoreData to see if it suits your needs
