Marko Markovic
Marko Markovic

Reputation: 147

tableview not updating current state

Click on cell is opening new ViewController with proper value from each cell

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
    let singleMovie = movieList[indexPath.row]
    getCredits(movieId: singleMovie.id)

    var directorName = ""
    creditResponse?.crew.forEach({ singleCredit in
        if singleCredit.knownForDepartment == .directing{
            directorName = singleCredit.name
        }
        
    })
    let detailVc = DetailViewController(title: singleMovie.title, imageUrl: singleMovie.posterPath,description: singleMovie.overview, groups: checkGroups(groups: singleMovie.genreIds), director: directorName)
    navigationController?.pushViewController(detailVc, animated: true)
}

With function below, I am adding value to creditResponse which is CreditsResponse type.

func getCredits(movieId: Int) {
    networkManager.getDirector(from: "https://api.themoviedb.org/3/movie/", movieId: movieId) { (creditResponse) in
        guard let credit = creditResponse else {
            return
        }
        self.creditResponse = credit
    }
    
}

With function below I am fetching data from URL.

func getDirector(from url: String, movieId: Int, _ completed: @escaping (CreditsResponse?) -> Void){
    guard let safeUrl = URL(string: url + "\(String(movieId))/credits" + apiid) else {return}
    URLSession.shared.dataTask(with: safeUrl){ data, urlResponse, error in
        guard let safeData = data, error == nil, urlResponse != nil else {
            completed(nil)
            return
        }
        if let decodedObject: CreditsResponse = SerializationManager().parse(jsonData: safeData){
            completed(decodedObject)
        }else{
            completed(nil)
        }
    }.resume()
}

Problem is that when I select first cell creditReponse is nil, and after selecting second cell there are value from first cell that I select (it presents always previous value)

Also, when new ViewController is pushed, its content is shown in transition before root controller is moved like in picture below:

Image

Upvotes: 0

Views: 52

Answers (2)

Tarun Tyagi
Tarun Tyagi

Reputation: 10112

Change 1

Add a completion parameter to following.

func getCredits(movieId: Int, completion: @escaping (() -> Void)) {
    networkManager.getDirector(from: "https://api.themoviedb.org/3/movie/", movieId: movieId) { (creditResponse) in
        guard let credit = creditResponse else {
            return
        }
        self.creditResponse = credit
        DispatchQueue.main.async {
            completion()
        }
    }
}

Change 2

Wait for the API call to complete before moving to next screen.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
    let singleMovie = movieList[indexPath.row]
    getCredits(movieId: singleMovie.id, completion: { [weak self] in
        guard let self = self else { return }
        var directorName = ""
        self.creditResponse?.crew.forEach({ singleCredit in
            if singleCredit.knownForDepartment == .directing {
                directorName = singleCredit.name
            }
        })
        let detailVc = DetailViewController(title: singleMovie.title, imageUrl: singleMovie.posterPath, description: singleMovie.overview, groups: checkGroups(groups: singleMovie.genreIds), director: directorName)
        self.navigationController?.pushViewController(detailVc, animated: true)
    })
}

Upvotes: 1

SeaSpell
SeaSpell

Reputation: 758

The problem is creditResponse gets set, but it gets set too late you are making an async call and then leaving. Local var directorName then gets copied as "" and goes out of scope. When the network call comes back you need to update the detailVC. Consider passing just singleMovie and handling your async calls in detailVC. Keep in mind you can only update the view from the main thread when the async block returns.

Upvotes: 0

Related Questions