【问题标题】:How to pass in extra arguments to a custom UIView that is linked to a XIB file?如何将额外参数传递给链接到 XIB 文件的自定义 UIView?
【发布时间】: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 我已经尝试过你所说的并且遇到了另一个错误,我已经在上面的帖子中添加了更新,我可以知道如何纠正这个错误吗?谢谢!
  • 你需要设置图片。对吗?

标签: ios swift uiview storyboard xib


【解决方案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 似乎有问题。请参阅stackoverflow.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:]:此类不符合键值编码的键海报。 '我该如何纠正这个问题?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-13
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-31
    • 2012-12-24
    • 1970-01-01
    相关资源
    最近更新 更多