在 iOS 中,将视图添加为子视图与将视图分配给视图属性之间有区别吗?

Posted

技术标签:

【中文标题】在 iOS 中,将视图添加为子视图与将视图分配给视图属性之间有区别吗?【英文标题】:In iOS, is there a difference between adding a view as a subview versus assigning a view to the view property? 【发布时间】:2017-11-29 18:47:56 【问题描述】:

我试图弄清 ios 编程中的任何歧义,所以我看过一些教程,其中开发人员将他们的主视图分配给 viewController 的 view 属性,如下所示:

let sceneView = ARSCNView(frame: self.view.frame)
view = sceneView

但是我也看到开发人员将他们的主视图作为子视图添加到视图属性中,如下所示:

let sceneView = ARSCNView(frame: self.view.frame)
view.addSubView(sceneView)

这两个过程是相同的还是不同的?

【问题讨论】:

【参考方案1】:

它们并不相同,但在功能上它们是相似的。以下是不同之处的演示:

override func viewDidLoad() 
    super.viewDidLoad()

    self.view.backgroundColor = UIColor.blue
    let sceneView = UIView(frame: self.view.frame)
    sceneView.backgroundColor = UIColor.red
    self.view.addSubview(sceneView)

在调试器中:

对比替换:

override func viewDidLoad() 
    super.viewDidLoad()

    self.view.backgroundColor = UIColor.blue
    let sceneView = UIView(frame: self.view.frame)
    sceneView.backgroundColor = UIColor.red
    self.view = sceneView

在调试器中:

所以你看到虽然它被子视图隐藏了,但是当sceneView被添加为子视图时,原来的蓝色视图仍然在视图层次结构中。但是,当您替换视图时,原始的蓝色视图根本不再是视图层次结构的一部分。

注意:如果您想在 loadView() 中设置视图,而不是像 rmaddy 建议的那样在 viewDidLoad() 中替换视图,这样的方法会起作用。诀窍是获得正确的框架 - 例如,如果您在导航控制器中,框架会有所不同。

override func loadView() 
    let sceneView = UIView(frame: UIScreen.main.bounds)
    sceneView.backgroundColor = UIColor.red
    self.view = sceneView

【讨论】:

老实说,这两种方式都不重要。从技术上讲,用您自己的视图替换视图会产生更简单的视图层次结构,因此我通常会推荐这种方法,但我不知道 Apple 对此有何官方立场。 不要在viewDidLoad 中重新分配view。如果您希望将自定义视图分配给 view 属性,请覆盖 loadView 并在那里执行。 直接替换视图控制器的视图是个坏主意。举个例子,这意味着视图的引用计数下降到零,导致它被释放。这反过来会导致子视图被释放。所有的 IBOutlets(默认情况下是弱隐式展开的选项)也将被释放,因此下次尝试引用一个插座时,您将崩溃,因为隐式展开将失败。照 rmaddy 说的做,并覆盖 loadView 以加载自定义视图层次结构。 我认为在您完全替换视图的情况下,您希望并期望旧的替换视图被释放。您也不会替换具有子视图或引用为 IBOutlets 的子视图的视图。在这种情况下,您只需以编程方式添加子视图(WKWebView 就是一个常见的例子)。 iOS 使用引用计数。当方法退出其作用域时,任何引用计数不大于 0 的内存都会被释放和回收。当您将视图控制器上的视图引用设置为 loadView 中的新视图时,或者将视图添加为 viewDidLoad 中的子视图时,您正在增加新视图的引用计数,因此它不会被释放。

以上是关于在 iOS 中,将视图添加为子视图与将视图分配给视图属性之间有区别吗?的主要内容,如果未能解决你的问题,请参考以下文章

自定义 UIView(.xib) 在 UITableViewCell 中添加为子视图后自动更改框架

无法将自己添加为子视图

将 UIImagePickerController 添加为子视图

将 UIView 添加为子视图并在 Swift 中确定它们在视图层次结构中的位置

UIView:将 UIViewController 的视图添加为子视图并将其删除

添加为子视图的 UILabel 数量遇到限制