UITableViewAlertForLayoutOutsideViewHierarchy错误:仅警告一次(iOS 13 GM)

Cri*_*sei 8 tableview ios swift ios13

执行Segue时,iOS13出现了一个奇怪的错误,我无法弄清这是什么意思,也找不到有关此错误的任何文档。问题在于,这似乎会导致很大的延迟(几秒钟),直到执行segue。

2019-09-11 22:45:38.861982 + 0100 Thrive [2324:414597] [TableView]仅警告一次:通知UITableView布局其可见单元格和其他内容,而不必使用视图层次结构(表视图或其其中之一)超级视图尚未添加到窗口中)。这可能会由于迫使表视图内的视图在没有准确信息(例如表视图边界,特征收集,布局边距,安全区域插图等)的情况下加载和执行布局而导致错误,并且还会由于额外的布局传递而导致不必要的性能开销。在UITableViewAlertForLayoutOutsideViewHierarchy上创建一个符号断点,以在调试器中捕获该断点,并查看引起此情况的原因,因此,如果可能,您可以完全避免执行此操作,或者将其推迟到将表视图添加到窗口中。表格视图:层=; contentOffset:{0,0}; contentSize:{315,118}; AdjustedContentInset:{0,0,0,0}; dataSource:>

我正在使用Hero,但是我尝试禁用它并使用常规的Segue,但这并没有阻止这种滞后。

启动segue的代码是didSelectRowAt

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if indexPath.section == 0 {
            selectedCell = realIndexFor(activeGoalAt: indexPath)
            performSegue(withIdentifier: "toGoalDetails", sender: nil)
        } else if indexPath.section == 1 {
            selectedCell = indexPath.row
            performSegue(withIdentifier: "toIdeaDetails", sender: nil)
        } else {
            selectedDecision = indexPath.row
            hero(destination: "DecisionDetails", type: .zoom)
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后,目标VC的viewDidLoad或viewWillAppear中的任何代码都不会以任何方式影响这一点(我尝试将它们全部注释掉,没有任何区别。

知道是什么原因造成的吗?我可以分享任何其他需要的细节。

谢谢。

den*_*cka 11

对于使用 的人DiffableDataSource,设置animatingDifferencesfalse并且警告将消失。

dataSource.apply(snapshot, animatingDifferences: false)

  • 非常感谢你,它拯救了我的一天。对于那些想要之后有动画的人,可以这样使用:`dataSource.apply(snapshot, animatingDifferences: tableView.window != nil)` (4认同)

Min*_*pps 7

这是我发生的,因为我在viewWillAppear(:)方法中注册了用于更改方向通知的设备我将注册移到了viewDidAppear( :)中,并且Xcode不再在断点处停止。

我可以说的是,当视图已经可见时,可以运行布局更改。

  • 正如您所说,当您在 viewDidAppear 而不是 viewWillAppear 中进行更新时,当视图已经可见时就会发生布局更改,从而导致非常不稳定的用户体验。我宁愿说这个警告是 iOS 中的一个错误。在 Apple 反馈助手上发布错误,并忽略警告。 (4认同)

Gal*_*her 7

像@joe-h 一样,我也收到了这个错误,而且我也很惊讶,因为他展示的 unwind 方法被许多开发人员使用 + 在一些重要的 Apple iOS 示例代码中。

我的代码中的触发线(@joe-h,我猜你的也很可能)是 selectedIndexPath 处的 tableView.reloadRows(这是一个未包装的 tableView.indexPathForSelectedRow):

tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果您在更新现有 tableView 行中的值(这是上述 Apple FoodTracker 教程中的一种方法,以及 Apple 的“人人能编码”系列中使用的方法)后展开,则注释掉该行不是一种选择。如果您不重新加载行,那么您的更改将不会显示在 tableView 中。在 unwind 中注释掉重新加载后,我添加了一个带有以下代码的 viewDidAppear,这似乎可以解决问题:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    if let selectedIndexPath = tableView.indexPathForSelectedRow {
        tableView.reloadRows(at: [selectedIndexPath], with: .automatic)
    }
}
Run Code Online (Sandbox Code Playgroud)

我欢迎就这是否是一种合理的方法发表评论,但就目前而言,这似乎奏效了。


Ami*_*eza 6

由于在不可见时更新表视图或集合视图,例如当它在父视图控制器上时,可能会发生此警告。为了解决这个问题,首先,我在视图控制器中创建了一个属性,包含表视图来检查视图控制器是否可见,如下所示:

var isVisible: Bool = false

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.isVisible = true
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.isVisible = false
}
Run Code Online (Sandbox Code Playgroud)

然后在数据源委托中,在对更改做出反应之前,首先检查视图控制器是否可见。如果不是,请不要进行任何更新。例如

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    guard isVisible else { return }
    tableView.beginUpdates()
}
Run Code Online (Sandbox Code Playgroud)

在对 tableView 进行任何更改之前,您应该检查该可见性。例如,在 NSFetchedResultsController 的情况下,它必须在我们已经实现的所有委托回调中完成。

更新

我最近发现如果你用动画 false 更新 table view,即使它不可见,也不会有任何警告。

  • +1“如果动画为假,即使它不可见,也不会出现任何警告。” - 你应该将此评论加粗并将其放在顶部,它是金色的。 (2认同)

小智 6

我的项目也有同样的错误;具有可区分数据源的 tableView。一直在窃听它几个小时。问题在于更新快照,更具体地说是在后台线程(默认)上。在主线程强制更新数据源解决了这个问题!希望这可以帮助那里的人!

    func updateData(on annotations: [Annotation]) {
        var snapshot = NSDiffableDataSourceSnapshot<AnnotationType, Annotation>()
        //Append available sections
        AnnotationType.allCases.forEach { snapshot.appendSections([$0]) }

        //Append annotations to their corresponding sections
        annotations.forEach { (annotation) in
            snapshot.appendItems([annotation], toSection: annotation.type as AnnotationType)
        }

        //Force the update on the main thread to silence a warning about tableview not being in the hierarchy!
        DispatchQueue.main.async {
            self.dataSource.apply(snapshot, animatingDifferences: true)
        }
    }
Run Code Online (Sandbox Code Playgroud)