UIViewController setView nil 自动从superview中移除

UIViewController setView nil automatically removes from superview

在 UIViewController 上调用 setView 会自动从其父视图中删除当前视图。我找不到这个记录。在我的例子中,我想在维护我的视图结构的同时动态地将一个 UIViewController 对象交换为另一个对象。我原本打算将视图重新链接到新控制器,但可惜,这不起作用。

一般来说,从其父视图中自动删除视图似乎是一个明智的决定。不过文档应该反映这一点。

(对于任何认为以这种方式交换视图控制器对象是一个非常糟糕的主意的人,让我补充一点,我要交换的控制器是现有控制器的子类。这种方法非常适合添加一个视图的功能是另一个视图的扩展。)

我是这样解决的:

UIView *viewToKeep = self.viewController.view;
UIView *superview = viewToKeep.superview;
self.viewController.view = nil;  // removes the view from its superview

UIViewController *swapInViewController = [[UIViewController alloc] init];
swapInViewController.view = viewToKeep;
[superview addSubview: viewToKeep];
[viewToKeep applyConstraintsToFillSuperview];  // a helper to add auto layout constraints that make the view always fill it's parent
self.viewController = swapInViewController;

这样做肯定有悖于 UIKit 的原则,因此很可能是个坏主意。

也就是说,这里有一些东西可以防止视图被自动删除,这意味着您不需要使用 addSubview 将它放回原来的位置。

仅针对您在下方看到的内容进行了测试,买者自负等。在 Swift:

class View: UIView {
    var preventRemovalFromSuperView = false
    override func removeFromSuperview() {
        if !preventRemovalFromSuperView {
            super.removeFromSuperview()
        }
        preventRemovalFromSuperView = false
    }
}

let vc1 = UIViewController()
let vc2 = UIViewController()
let sv = UIView()
let v = View()

// Existing hierarchy
sv.addSubview(v)
vc1.view = v

// Swap view controllers
v.preventRemovalFromSuperView = true // Prevent automatic removal
vc1.view = nil // Prevent UIViewControllerHierarchyInconsistency exception
vc2.view = v

// Check that view was not automatically removed
v.isDescendantOfView(sv) // true