【问题标题】:My subview can't be added to a UIView that is a subView of a UIView.xib file, it returns nil我的子视图无法添加到作为 UIView.xib 文件的子视图的 UIView,它返回 nil
【发布时间】:2019-12-02 06:08:54
【问题描述】:

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

但是,当从 FileViewController.swift 调用它时,我得到一个 nil 结果。

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)

但它在 customView.webViewContainer 的行上返回 nil:

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

在覆盖函数 loadView() 上加载 customView 时,webViewContainer 是否应该已经实例化?

【问题讨论】:

  • init FileView 带有框架矩形和检查
  • 仍然返回 nil,我认为这确实与 Andreas 关于弱引用的建议有关。
  • 在 setUp 方法中添加一个 print 语句,以查看在崩溃之前是否正确调用了 create 语句。如果确实如此,那么正如 Andreas 指出的那样,这可能是参考问题
  • 是的,它确实在崩溃前被调用。表示它正在被调用,但也被 ARC 清除。

标签: swift addsubview


【解决方案1】:

问题是您的webViewContainerweak 参考:

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

如果

  • 您正在使用 XIB 文件
  • 某人(例如视图控制器)保持对顶视图的强引用
  • 出口是视图层次结构的一部分。

但是在您的情况下,在setup 中,您创建了一个视图实例,将其存储在弱引用中,然后 ARC(引用计数机制)将发现不再有对 @ 的强引用987654325@ 并因此清除内存,产生nil 引用。

所以你需要以某种方式保持一个强有力的参考;在最简单的情况下,只需跳过插座中的 weak 引用说明符。

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

【讨论】:

  • 谢谢你,我会试试你的建议,看看是否有一个强有力的参考将使它起作用!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多