skip to Main Content

I have two UIView and I want to add detailsView as subview with other view. I am getting following error:

Cannot convert value of type ‘MovieDetailsDisplayViewController.detailsView.Type’ to expected argument type ‘MovieDetailsDisplayViewController.View’

View model code ..

enum MoviesDetailsViewModelState {
    case loading(Movie)
    case loaded(MovieDetails)
    case pageLoaded(Page<Movie>)
    case error

    var title: String? {
        switch self {
        case .loaded(let movie):
            return movie.title
        case .loading(let movie):
            return movie.title
        case .error:
            return nil
        case .pageLoaded:
            return nil
        }
    }

    var movie: MovieDetails? {
        switch self {
        case .loaded(let movie):
            return movie
        case .loading, .error:
            return nil
        case .pageLoaded:
            return nil
        }
    }
    
    var page: Page<Movie>? {
        
        switch self {
        case .loading, .error, .loaded:
            return nil
        case .pageLoaded(let page):
          return page
        }
    }
}

final class MoviesDetailsViewModel {

    private let apiManager: APIManaging
    private let initialMovie: Movie
    var moviePage = [Movie]()

    init(movie: Movie, apiManager: APIManaging = APIManager()) {
        self.initialMovie = movie
        self.apiManager = apiManager
        self.state = .loading(movie)
    }

    var updatedState: (() -> Void)?

    var state: MoviesDetailsViewModelState {
        didSet {
            updatedState?()
        }
    }

    func fetchData() {
        apiManager.execute(MovieDetails.details(for: initialMovie)) { [weak self] result in
            guard let self = self else { return }
            switch result {
            case .success(let movieDetails):
                self.state = .loaded(movieDetails)
            case .failure:
                self.state = .error
            }
        }
    }
    
    func fetchSimilarMovie() {
        apiManager.execute(Movie.similiar(for: initialMovie.id)) { [weak self]  result in
            guard let self = self else { return }
            switch result {
            case.success(let page):
                self.state = .pageLoaded(page)
                self.moviePage = page.results
                print(moviePage)
            case .failure(let error):
                self.state = .error
                print(error)
            }
        }
    }
}

Here is the code for both views:

    final class MovieDetailsDisplayViewController: UIViewController {
    
    let movieDetails: MovieDetails
    
    init(movieDetails: MovieDetails) {
        self.movieDetails = movieDetails
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func loadView() {
        view = ParentView()
        view = DetailsView(coder: <#NSCoder#>)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        (view as? ParentView)?.configure(movieDetails: movieDetails)
        view.addSubview(DetailsView)

    }
    
    private class ParentView: UIView {
    
        let scrollView = UIScrollView()
        let backdropImageView = UIImageView()
        let titleLabel = UILabel()
        let overviewLabel = UILabel()
        let similarLabel = UILabel()
        private lazy var contentStackView = UIStackView(arrangedSubviews: [backdropImageView, titleLabel, overviewLabel, similarLabel])
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
        
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            commonInit()
        }
        
        private func commonInit() {
            backgroundColor = .white
            
            backdropImageView.contentMode = .scaleAspectFill
            backdropImageView.clipsToBounds = true
            
            titleLabel.font = UIFont.Heading.medium
            titleLabel.textColor = UIColor.Text.charcoal
            titleLabel.numberOfLines = 0
            titleLabel.lineBreakMode = .byWordWrapping
            titleLabel.setContentHuggingPriority(.required, for: .vertical)
            
            overviewLabel.font = UIFont.Body.small
            overviewLabel.textColor = UIColor.Text.grey
            overviewLabel.numberOfLines = 0
            overviewLabel.lineBreakMode = .byWordWrapping
            
            similarLabel.font = UIFont.Body.smallSemiBold
            similarLabel.textColor = UIColor.Text.charcoal
            similarLabel.numberOfLines = 0
            similarLabel.lineBreakMode = .byWordWrapping
            
            contentStackView.axis = .vertical
            contentStackView.spacing = 24
            contentStackView.setCustomSpacing(8, after: titleLabel)
            
            setupViewsHierarchy()
            setupConstraints()
        }
        
        private func setupViewsHierarchy() {
            addSubview(scrollView)
            scrollView.addSubview(contentStackView)
        }
        
        private func setupConstraints() {
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            backdropImageView.translatesAutoresizingMaskIntoConstraints = false
            contentStackView.translatesAutoresizingMaskIntoConstraints = false
            
            NSLayoutConstraint.activate(
                [
                    scrollView.topAnchor.constraint(equalTo: topAnchor),
                    scrollView.leadingAnchor.constraint(equalTo: leadingAnchor),
                    scrollView.bottomAnchor.constraint(equalTo: bottomAnchor),
                    scrollView.trailingAnchor.constraint(equalTo: trailingAnchor),
                    
                    backdropImageView.heightAnchor.constraint(equalTo: backdropImageView.widthAnchor, multiplier: 11 / 16, constant: 0),
                    
                    contentStackView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 24),
                    contentStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
                    contentStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
                    contentStackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -24)
                ]
            )
            
            scrollView.layoutMargins = UIEdgeInsets(top: 24, left: 16, bottom: 24, right: 16)
            preservesSuperviewLayoutMargins = false
        }
        
        func configure(movieDetails: MovieDetails) {
            backdropImageView.dm_setImage(backdropPath: movieDetails.backdropPath)
            
            titleLabel.text = movieDetails.title
            
            overviewLabel.text = movieDetails.overview
        }
        
    }
    
    private class DetailsView: UIView, UICollectionViewDataSource, UICollectionViewDelegate {
        
        let viewModel: MoviesDetailsViewModel
        init(viewModel: MoviesDetailsViewModel) {
            self.viewModel = viewModel
            super.init()
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        fileprivate let collectionView:UICollectionView = {
            let layout = UICollectionViewFlowLayout()
            layout.scrollDirection = .horizontal
            let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
            cv.translatesAutoresizingMaskIntoConstraints = false
            cv.register(SimilierMovieCell.self, forCellWithReuseIdentifier: "CompanyCell")
            cv.backgroundColor = .lightGray
            return cv
        }()
        
        
        private func setUpUI() {
            
            addSubview(collectionView)
            
            //Add constraint
            collectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
            collectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
            collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true
            collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
           
        }
        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
            return CGSize(width: collectionView.frame.width/2.5, height: collectionView.frame.width/2)
        }
        
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            let items = viewModel.moviePage.count
            return items
        }
        
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SimilierMovieCell.identifier, for: indexPath) as? SimilierMovieCell
            
            let listMovie = viewModel.moviePage[indexPath.row]
            print(listMovie)
            cell?.configure(listMovie)
            return cell ?? SimilierMovieCell()
        }
    }
}

Here is the screenshot of the error.

enter image description here

2

Answers


  1. It’s a bit hard to follow your code, but the line that is giving the error is wrong. It reads View.addSubview(detailsView). The bit View is your View class, not your current view controller’s content view. It should probably read view.addSubview(detailsView) (with view in lower case.)

    (Swift is case-sensitive, and View refers to your UIView class, where view in a view controller is shorthand for self.view, or a reference to the view controller’s content view.)

    Login or Signup to reply.
  2. You report this error:

    Cannot convert value of type ‘MovieDetailsDisplayViewController.detailsView.Type’ to expected argument type ‘MovieDetailsDisplayViewController.View’

    That is a result of the line that says:

    view.addSubview(DetailsView)
    

    DetailsView is the name of a type. But you need to set it to be an instance of the UIView type:

    let movie = …
    let viewModel = MoviesDetailsViewModel(movie: movie)
    let detailsView = DetailsView(viewModel: viewModel)
    view.addSubview(detailsView)
    

    You have not shared where this Movie parameter of the MoviesDetailsViewModel comes from. Perhaps the movieDetails property?

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search