I'm trying to make MVVM from MVC, but I can't transfer the information that I could transfer before, through prepare. What is the reason? How can I fix ?
MainViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail", let detailVC = segue.destination as? DetailViewController, let indexPath = tableView.indexPathForSelectedRow {
let pokemon = viewModel.pokemons[indexPath.row]
detailVC.viewModel?.pokemonId = "\(indexPath.row + 1)"
detailVC.viewModel?.name = pokemon.name
detailVC.viewModel?.imageURL = viewModel.getPokemonSpritesURL(for: indexPath.row)
}
}
DetailViewModel
class DetailViewModel {
// MARK: - Properties
var pokemonId: String
let apiService: PokeAPIService
var name: String?
var abilities: [Ability]?
var imageURL: URL?
// MARK: - Initializers
init(pokemonId: String, apiService: PokeAPIService) {
self.pokemonId = pokemonId
self.apiService = apiService
}
// MARK: - Public Methods
func fetchPokemonDetails(completion: @escaping () -> Void) {
apiService.getPokemon(by: pokemonId) { [weak self] response in
guard let self = self else { return }
self.name = response.name
self.abilities = response.abilities
if let urlString = response.sprites?.frontDefault {
self.imageURL = URL(string: urlString)
}
completion()
}
}
}
DetailViewController
var viewModel: DetailViewModel?
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var abilitiesNameLabel: UILabel!
@IBOutlet weak var abilitiesNameLabel2: UILabel!
// MARK: - Private Methods
func configureView() {
viewModel?.fetchPokemonDetails(completion: { [weak self] in
guard let self = self else { return }
DispatchQueue.main.async {
self.nameLabel.text = self.viewModel?.name
self.abilitiesNameLabel.text = self.viewModel?.abilities?[0].ability?.name
self.abilitiesNameLabel2.text = self.viewModel?.abilities?[1].ability?.name
if let imageURL = self.viewModel?.imageURL {
self.loadImage(from: imageURL)
}
}
})
}
func loadImage(from url: URL) {
URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in
guard let self = self, let data = data else { return }
DispatchQueue.main.async {
self.imageView.image = UIImage(data: data)
}
}.resume()
}
When I switch back to MVC I don't have any problems. I can't find where I'm doing wrong It seems like I'm missing something small but I can't figure it out.
Your problem is here
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail", let detailVC = segue.destination as? DetailViewController, let indexPath = tableView.indexPathForSelectedRow {
let pokemon = viewModel.pokemons[indexPath.row]
detailVC.viewModel?.pokemonId = "\(indexPath.row + 1)"
detailVC.viewModel?.name = pokemon.name
detailVC.viewModel?.imageURL = viewModel.getPokemonSpritesURL(for: indexPath.row)
}
}
at this step detailVC.viewModel
is nil
and setting to VM some properties doesn't have any result. So in this method you need to create instance of DetailViewModel
with all required data and set it to detailVC
like this:
detailVC.viewModel = DetailViewModel(id: id, name: name, url: url)