Search code examples
iosswiftuiviewstoryboardxib

How to pass in extra arguments to a custom UIView that is linked to a XIB file?


I currently have a data type called MovieCard that holds all the data regarding a movie and it needs to be displayed onto a card, aka a UIView. I have created a custom UIView class called MovieCardView and have linked it to a XIB file through File's Owner. The MovieCardView contains a few labels and an image view.

My question is, what do I have to write inside the MovieCardView file (I'm confused regarding bundle loading) and how can I pass in the movie card to the MovieCardView? I want the MovieCardView to utilise the data present in the movie card to set some values for the labels and ImageView in the MovieCardView.

This is what is in my view controller and what I wish to happen

func koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView {
        
        let movieCard = cards[index]

        return MovieCardView(movieCard: movieCard)
    }

And my current view file looks like this

class MovieCardView: UIView {
        @IBOutlet var moviePoster: UIImageView!
        @IBOutlet var movieTitle: UILabel!
        @IBOutlet var movieYear: UILabel!

       override init(frame: CGRect) {
           super.init(frame: frame)
           commonInit()
       }

      required init?(coder aDecoder: NSCoder) {
          super.init(coder: aDecoder)
          commonInit()
      }

      func commonInit() {
         Bundle.main.loadNibNamed("MovieCardView", owner: self, options: nil)
       }

}

I'm not sure how to modify the code to allow me to pass in the movieCard from my view controller and programatically set the IBOutlets to certain properties of my movieCard. I also do not wish to programatically change the frame at all. Any help would be appreciated. Thank you!

Update I have tried the following

import UIKit
import Kingfisher

class MovieCardView: UIView {
    @IBOutlet weak var poster: UIImageView!
    
    let movieCard: MovieCard
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
   required init?(coder aDecoder: NSCoder) {
       super.init(coder: aDecoder)
       commonInit()
   }

    func commonInit() {
        Bundle.main.loadNibNamed("MovieCardView", owner: self, options: nil)
        
        guard let posterString = movieCard.poster_path else {
            return
        }
        
        let urlString = "https://image.tmdb.org/t/p/w300" + posterString
        
        guard let posterImageURL = URL(string: urlString) else {
            return
        }
        
        poster.kf.setImage(with: posterImageURL)
        
    }

 
}

I am getting errors saying Property 'self.movieCard' not initialized at super.init call for both override init and required init methods. How do I rectify this? Thanks!


Solution

  • I am getting errors saying Property 'self.movieCard' not initialized at super.init call for both override init and required init methods.

    The Swift compiler will prevent you from creating objects that aren't fully initialized, so before you initialize the superclass you need to provide values for your class's properties.

    How do I rectify this?

    You need to either provide a value for your movieCard property in your initializers before you call super.init, or make movieCard optional so that the compiler will let you leave it unset until later. For example, you could change the declaration to:

    var movieCard = MovieCard()
    

    to just give it an empty MovieCard instance, and make it var so that you can change it later on. You could also mark the variable lazy so that the empty MovieCard isn't actually created unless you try to access the value of the property:

    lazy var movieCard = MovieCard()