我的子视图无法添加到作为 UIView.xib 文件的子视图的 UIView,它 returns nil

My subview can't be added to a UIView that is a subView of a UIView.xib file, it returns nil

我有两个 Swift 文件,一个叫 FileView.swift,另一个叫 FileViewController.swift。使用 MVC 架构,我正在尝试将 FileViewController.swift 的子视图添加到 FileView.swift 的 webViewContainer:UIView!这是来自 XIB 文件的 IBOutlet。

但是,当从 FileViewController.swift 调用它时,我得到的结果为零。

class FileView: UIView {

    @IBOutlet weak var webViewContainerHeight: NSLayoutConstraint!
    @IBOutlet weak var webViewContainerWidth: NSLayoutConstraint!
    @IBOutlet weak var closeBttnWidth: NSLayoutConstraint!
    @IBOutlet weak var closeBttnHeight: NSLayoutConstraint!
    @IBOutlet weak var webViewContainer: UIView!
    @IBOutlet weak var closeButton: UIButton!

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

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

    private func setup() {
        webViewContainer = UIView(frame: CGRect(x: 0, y: 0, width: 500, height: 350))
    }
class FileViewController: UIViewController, WKNavigationDelegate {

    var webView = WKWebView()
    var campaignUrl = ""
    var finalCampaignUrl = ""

    lazy var customView: FileView = {
        let customView = FileView()
        return customView
    }()

    override func loadView() {
        self.view = self.customView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        webViewModal()
    }

func webViewModal () {
        if UIDevice.current.userInterfaceIdiom == .pad {
            let deviceWidth = UIScreen.main.bounds.width/3
            let deviceHeight = UIScreen.main.bounds.height/3
            customView.webViewContainerWidth.constant = 290 + deviceWidth
            customView.webViewContainerHeight.constant = 475 + deviceHeight
            customView.closeBttnWidth.constant = 55
            customView.closeBttnHeight.constant = 55
            customView.closeButton.layoutIfNeeded()
            customView.webViewContainer.layoutIfNeeded()
        }
        webView = Global.setWKWebViewInitWithConfig(frame: .zero)
        customView.webViewContainer.addSubview(webView)
        customView.webViewContainer.showSpinner(CGSize(width: 30 , height: 30), tintColor: UIColor.lightGray)
        webView.translatesAutoresizingMaskIntoConstraints = false
        let webViewHeightConstraint = NSLayoutConstraint(
            item: webView,
            attribute: .height,
            relatedBy: .equal,
            toItem: customView.webViewContainer,
            attribute: .height,
            multiplier: 1,
            constant: 0
        )
        let webViewWidthConstraint = NSLayoutConstraint(
            item: webView,
            attribute: .width,
            relatedBy: .equal,
            toItem: customView.webViewContainer,
            attribute: .width,
            multiplier: 1,
            constant: 0
        )
        let webViewLeftMarginConstraint = NSLayoutConstraint(
            item: webView,
            attribute: .leftMargin,
            relatedBy: .equal,
            toItem: customView.webViewContainer,
            attribute: .leftMargin,
            multiplier: 1,
            constant: 0
        )
        let webViewRightMarginConstraint = NSLayoutConstraint(
            item: webView,
            attribute: .rightMargin,
            relatedBy: .equal,
            toItem: customView.webViewContainer,
            attribute: .rightMargin,
            multiplier: 1,
            constant: 0
        )
        let webViewBottomMarginContraint = NSLayoutConstraint(
            item: webView,
            attribute: .bottomMargin,
            relatedBy: .equal,
            toItem: customView.webViewContainer,
            attribute: .bottomMargin,
            multiplier: 1,
            constant: 0
        )
        NSLayoutConstraint.activate([webViewHeightConstraint, webViewWidthConstraint, webViewLeftMarginConstraint, webViewRightMarginConstraint, webViewBottomMarginContraint])

        webView.navigationDelegate = self

        Global.initialLoadWithParam(ofWebView: webView, withURL: NSURL(string: campaignUrl)!)
        customView.closeButton.layer.cornerRadius = 0.9 * customView.closeButton.bounds.size.width
        customView.closeButton.backgroundColor = #colorLiteral(red: 0.003921568627, green: 0.1647058824, blue: 0.2666666667, alpha: 1)
        customView.closeButton.tintColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
        customView.webViewContainer.layer.cornerRadius = 15
        customView.webViewContainer.layer.masksToBounds = true
    }


我预计这应该添加

webView = Global.setWKWebViewInitWithConfig(frame: .zero)

customView.webViewContainer.addSubview(webView)

但它 returns nil 而不是 customView.webViewContainer 的行:

Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

当 customView 在 override func loadView() 上加载时,是否应该已经实例化 webViewContainer?

问题是您的 webViewContainerweak 参考:

class FileView: UIView {
    // ...
    @IBOutlet weak var webViewContainer: UIView!
    // ...
}

如果

这很好用
  • 您正在使用 XIB 文件
  • 某人(e.g.the 视图控制器)保持对顶视图的强引用
  • 插座是视图层次结构的一部分。

但是在你的情况下,在setup你创建了一个视图的实例,将它存储在弱引用中,然后ARC(引用计数机制)会发现没有任何强引用更多到 UIView 并因此清除内存,导致 nil 引用。

所以你需要以某种方式保持强引用;在最简单的情况下,只需跳过出口中的 weak 引用说明符。

但请记住,您可能需要做一些额外的事情来防止强引用循环。在你的情况下,如果你不使用 xib 文件,你可以删除所有 @IBOutlet 的东西并使 NSCoder 初始化程序只调用 fatalError,以防止任何创建来自 xib 文件。