如何将额外参数传递给链接到 XIB 文件的自定义 UIView?

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

我目前有一个名为 MovieCard 的数据类型,它包含有关电影的所有数据,它需要显示在卡片上,也就是 UIView。我创建了一个名为 MovieCardView 的自定义 UIView class,并通过文件所有者将其链接到 XIB 文件。 MovieCardView 包含一些标签和一个图像视图。

我的问题是,我必须在 MovieCardView 文件中写入什么(我对捆绑加载感到困惑)以及如何将电影卡传递给 MovieCardView?我希望 MovieCardView 利用电影卡中的数据为 MovieCardView 中的标签和 ImageView 设置一些值。

这是我的视图控制器中的内容,也是我希望发生的事情

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

        return MovieCardView(movieCard: movieCard)
    }

我当前的视图文件如下所示

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)
       }

}

我不确定如何修改代码以允许我从我的视图控制器传入 movieCard 并以编程方式将 IBOutlet 设置为我的 movieCard 的某些属性。我也根本不想以编程方式更改框架。任何帮助,将不胜感激。谢谢!

更新 我尝试了以下

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)
        
    }

 
}

我收到错误提示 属性 'self.movieCard' not initialized at super.init call for override init and required init methods。我该如何纠正这个问题?谢谢!

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

Swift 编译器会阻止您创建未完全初始化的对象,因此在初始化超级 class 之前,您需要为 class 的对象提供值属性。

How do I rectify this?

您需要在调用 super.init 之前在初始化程序中为 movieCard 属性 提供一个值,或者使 movieCard 可选,以便编译器允许你把它留到以后再设置。例如,您可以将声明更改为:

var movieCard = MovieCard()

只给它一个空的 MovieCard 实例,然后将其设为 var 以便您以后可以更改它。您还可以标记变量 lazy,这样除非您尝试访问 属性:

的值,否则实际上不会创建空的 MovieCard
lazy var movieCard = MovieCard()

Copy/paste将以下代码添加到您的项目中。

public extension UIView {
    
    class var bundle: Bundle { Bundle(for: self) }
    class var identifier: String { String(describing: self) }
    
    class var nibName: String { identifier }
    class var nib: UINib { UINib(nibName: nibName, bundle: bundle) }

    class func instantiateFromNib<T: UIView>() -> T {
        return nib.instantiate(withOwner: nil, options: [:])[0] as! T
    }
}

现在您可以在想要实例化您的自定义时执行此操作 UIView

let view: MovieCardView = MovieCardView.instantiateFromNib()

MovieCardView 开始,您可以删除所有 init 覆盖和 commonInit 方法。添加一种这样的方法。

func populateMovieCard(_ movieCard: MovieCard) {
    // populate your details on to UI here
}
import UIKit
import Kingfisher

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

    func setup(_ movieCard: MovieCard) {
         self.movieCard = movieCard
         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)
       }
}

// from controller when you initialising customview call this function from there like below

func koloda(_ koloda: KolodaView, viewForCardAt index: Int) -> UIView {
        
        let movieCard = cards[index]
        guard let customView = Bundle.main.loadNibNamed("MovieCardView", owner: nil, options: nil) as? MovieCardView else { return UIView() }

customView.setUp(movieCard);

        return customView
    }