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

Posted

技术标签:

【中文标题】如何将额外参数传递给链接到 XIB 文件的自定义 UIView?【英文标题】:How to pass in extra arguments to a custom UIView that is linked to a XIB file? 【发布时间】:2021-09-21 07:15:01 【问题描述】:

我目前有一个名为 MovieCard 的数据类型,它包含有关电影的所有数据,它需要显示在卡片上,也就是 UIView。我创建了一个名为 MovieCardView 的自定义 UIView 类,并通过 File's Owner 将其链接到 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 并以编程方式将 IBOutlets 设置为我的 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)
        
    

 

我收到错误消息,提示在 super.init 调用时未对重写 init 和所需的 init 方法初始化 Property 'self.movi​​eCard'。我该如何纠正这个问题?谢谢!

【问题讨论】:

为此您需要在MovieCardView 中声明一个变量并将其设置为commoninit() 嗨@jatinfl 你的意思是像 let movieCard: MovieCard 作为 IBOutlets 之后的一行,然后在 commonInit() 中设置 moviePoster = movieCard.poster 吗?我也可以检查捆绑加载代码是否正常?谢谢! 是的,试试这个,如果你卡在这里 ping 我。 嗨@jatinfl 我已经尝试过你所说的并且遇到了另一个错误,我已经在上面的帖子中添加了更新,我可以知道如何纠正这个错误吗?谢谢! 你需要设置图片。对吗? 【参考方案1】:

我收到错误消息,提示在 super.init 调用重写 init 和必需的 init 方法时未初始化 Property 'self.movi​​eCard'。

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

我该如何解决这个问题?

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

var movieCard = MovieCard()

只给它一个空的MovieCard 实例,并使其成为var,以便您以后可以更改它。您还可以标记变量 lazy 以便实际上不会创建空的 MovieCard,除非您尝试访问该属性的值:

lazy var movieCard = MovieCard()

【讨论】:

【参考方案2】:

将以下代码复制/粘贴到您的项目中。

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

【讨论】:

感谢您的回复。我在实现您的代码时遇到错误:由于未捕获的异常“NSUnknownKeyException”而终止应用程序,原因:“[ setValue:forUndefinedKey:]:此类不符合键值编码的键海报。 '我该如何纠正这个问题?我假设它与 xib 文件有关。 是的,您的 XIB 似乎有问题。请参阅***.com/questions/3088059/… 以解决您的问题。【参考方案3】:
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
    

【讨论】:

感谢您的回复。我在实现您的代码时遇到错误:由于未捕获的异常“NSUnknownKeyException”而终止应用程序,原因:“[ setValue:forUndefinedKey:]:此类不符合键值编码的键海报。 '我该如何纠正这个问题?

以上是关于如何将额外参数传递给链接到 XIB 文件的自定义 UIView?的主要内容,如果未能解决你的问题,请参考以下文章

如何将额外的额外参数传递给批处理文件?

如何将额外的参数传递给 django admin 自定义表单?

如何将参数传递给 JHipster 中的自定义错误消息?

如何将额外的参数传递给自定义UIView类以便在swift中进行初始化

如何使用 withColumn 将额外的参数传递给 UDF

Django将多个参数传递给If语句中的自定义模板过滤器