当视图未将自身添加到其子视图时,“无法将自身添加为子视图”崩溃(带有示例代码)

Posted

技术标签:

【中文标题】当视图未将自身添加到其子视图时,“无法将自身添加为子视图”崩溃(带有示例代码)【英文标题】:"Can't add self as subview" crash (with sample code) when view not adding itself to its subview 【发布时间】:2018-03-15 21:04:20 【问题描述】:

我可以用一个简单的项目重现这个问题 (Github Project)

主故事板有一个嵌入的ViewController,由最初的NavigationController 转换为一个segue。 Nav Controller 是初始的根控制器,在故事板视图中也是如此。

AppDelegate 类didFinishLaunchingWithOptions 方法实例化另一个导航控制器并以编程方式添加根视图控制器:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 

    let mainvc = MainViewController()
    let mainnc = UINavigationController(rootViewController: mainvc)

    self.window?.rootViewController = mainnc
    self.window?.makeKeyAndVisible()

    // Override point for customization after application launch.
    return true

上面实例化的 MainViewController 有以下代码。

class MainViewController : UITableViewController, UIAlertViewDelegate 

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
    

    convenience init() 
        self.init(nibName:nil, bundle:nil)
    

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) 
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    

    override func viewDidLoad() 
        super.viewDidLoad()

        let tableView = UITableView(frame:CGRect(x:0, y:0, width:self.view.bounds.size.width, height:self.view.bounds.size.height), style:.plain)
        self.tableView = tableView
        tableView.delegate = self
        tableView.dataSource = self
        tableView.separatorColor = UIColor(white:0.85, alpha:1)
        tableView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        tableView.register(UITableViewCell.self, forCellReuseIdentifier:"nephews")

        self.view.addSubview(tableView) // CRASH
    


运行代码时,我得到:

2018-03-15 13:35:57.083953-0700 CantAddSelfAsSubview[20953:14423557] *** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“无法将自身添加为子视图”

*** First throw call stack:
(
    0   CoreFoundation                      0x000000010957912b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x0000000105900f41 objc_exception_throw + 48
    2   CoreFoundation                      0x00000001095ee245 +[NSException raise:format:] + 197
    3   UIKit                               0x0000000106267582 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 122
    4   UIKit                               0x00000001062c6341 -[UITableView _addSubview:positioned:relativeTo:] + 127
    5   CantAddSelfAsSubview                0x0000000104fdf310 _T020CantAddSelfAsSubview20MyMainViewControllerC11viewDidLoadyyF + 1312
    6   CantAddSelfAsSubview                0x0000000104fdf6c4 _T020CantAddSelfAsSubview20MyMainViewControllerC11viewDidLoadyyFTo + 36
    7   UIKit                               0x000000010634546c -[UIViewController loadViewIfRequired] + 1235
    8   UIKit                               0x000000010638cffc -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 68
    9   UIKit                               0x000000010638d338 -[UINavigationController _startTransition:fromViewController:toViewController:] + 153
    10  UIKit                               0x000000010638e44f -[UINavigationController _startDeferredTransitionIfNeeded:] + 841
    11  UIKit                               0x000000010638f6d3 -[UINavigationController __viewWillLayoutSubviews] + 150
    12  UIKit                               0x00000001065ea4e2 -[UILayoutContainerView layoutSubviews] + 231
    13  UIKit                               0x000000010626ea6d -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1439
    14  QuartzCore                          0x000000010cb5e61c -[CALayer layoutSublayers] + 159
    15  QuartzCore                          0x000000010cb627ad _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 401
    16  QuartzCore                          0x000000010cae986c _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 364
    17  QuartzCore                          0x000000010cb16946 _ZN2CA11Transaction6commitEv + 500
    18  UIKit                               0x00000001061b826a __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 141
    19  CoreFoundation                      0x000000010951c05c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    20  CoreFoundation                      0x000000010950083b __CFRunLoopDoBlocks + 203
    21  CoreFoundation                      0x0000000109500014 __CFRunLoopRun + 1300
    22  CoreFoundation                      0x00000001094ff889 CFRunLoopRunSpecific + 409
    23  GraphicsServices                    0x000000010bd069c6 GSEventRunModal + 62
    24  UIKit                               0x000000010619d5d6 UIApplicationMain + 159
    25  CantAddSelfAsSubview                0x0000000104fe2027 main + 55
    26  libdyld.dylib                       0x000000010a717d81 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

由于我没有向自身添加视图,因此问题似乎出在其他地方。

我在 SO 上阅读了许多类似问题但没有重现代码的 cmets。有些人担心动画未完成时 NavController 中存在错误。我如何控制 segue 的动画,因为它由第一个导航控制器自动管理?

【问题讨论】:

【参考方案1】:

由于viewDidLoadself.viewself.tableViewtableView中的代码不正确,都是同一个视图。因此出现错误。

这是UITableViewController。它已经有一个表格视图。不要创建另一个。更新viewDidLoad如下:

override func viewDidLoad() 
    super.viewDidLoad()

    tableView.separatorColor = UIColor(white:0.85, alpha:1)
    tableView.register(UITableViewCell.self, forCellReuseIdentifier:"nephews")

您也不需要添加任何init 方法。

【讨论】:

谢谢。这个tableView.delegate = selftableView.dataSource = self真的不需要吗? 正确。 UITableViewController 使自己成为表视图的数据源并自动委托。您需要更改的另一件事是您在应用程序委托中创建MainViewController 的代码。您应该调用采用表格视图样式的初始化程序,而不是默认的空初始化程序。 @Laurent 虽然您确实需要在MainViewController 中实现各种数据源和委托方法才能使表格视图有用。 +1,我试图简明扼要地指出问题所在。我的主要项目更丰富 :-) 我将使用 MainViewController(style: .plain)

以上是关于当视图未将自身添加到其子视图时,“无法将自身添加为子视图”崩溃(带有示例代码)的主要内容,如果未能解决你的问题,请参考以下文章

向其子视图(即 UILabel)添加约束时,无法保持集合视图单元格的固定大小

如何使 iOS 子视图将自身添加到视图中

未将图像从 json 文件加载到我的列表视图

MVC 5 Razor 视图未将 bool 绑定到输入

滚动 UIScrollView 会更改其子视图框架

移动子视图时,如何将其子视图保留在其父视图中的同一位置?