我的子视图无法添加到作为 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?
问题是您的 webViewContainer
是 weak
参考:
class FileView: UIView {
// ...
@IBOutlet weak var webViewContainer: UIView!
// ...
}
如果
这很好用
- 您正在使用 XIB 文件
- 某人(e.g.the 视图控制器)保持对顶视图的强引用
- 插座是视图层次结构的一部分。
但是在你的情况下,在setup
你创建了一个视图的实例,将它存储在弱引用中,然后ARC(引用计数机制)会发现没有任何强引用更多到 UIView
并因此清除内存,导致 nil
引用。
所以你需要以某种方式保持强引用;在最简单的情况下,只需跳过出口中的 weak
引用说明符。
但请记住,您可能需要做一些额外的事情来防止强引用循环。在你的情况下,如果你不使用 xib
文件,你可以删除所有 @IBOutlet
的东西并使 NSCoder
初始化程序只调用 fatalError
,以防止任何创建来自 xib
文件。
我有两个 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?
问题是您的 webViewContainer
是 weak
参考:
class FileView: UIView {
// ...
@IBOutlet weak var webViewContainer: UIView!
// ...
}
如果
这很好用- 您正在使用 XIB 文件
- 某人(e.g.the 视图控制器)保持对顶视图的强引用
- 插座是视图层次结构的一部分。
但是在你的情况下,在setup
你创建了一个视图的实例,将它存储在弱引用中,然后ARC(引用计数机制)会发现没有任何强引用更多到 UIView
并因此清除内存,导致 nil
引用。
所以你需要以某种方式保持强引用;在最简单的情况下,只需跳过出口中的 weak
引用说明符。
但请记住,您可能需要做一些额外的事情来防止强引用循环。在你的情况下,如果你不使用 xib
文件,你可以删除所有 @IBOutlet
的东西并使 NSCoder
初始化程序只调用 fatalError
,以防止任何创建来自 xib
文件。