簡體   English   中英

UITableViewAlertForLayoutOutsideViewHierarchy 當 UITableView 沒有 window iOS13

[英]UITableViewAlertForLayoutOutsideViewHierarchy when UITableView doesn't have window iOS13

我開始在 iOS13 上收到警告(下)。 I have noticed that this warning pops up because UITableView 's window is null (another tab is selected, pushed detailed view controller on table selection...). 我正在嘗試從NSFetchedResultController委托更新UITableView 在 iO13 上執行此操作以保持表格更新的正確方法是什么?

下面的代碼在以前的版本中運行良好。

PS:任何一種beginUpdatesreloadRowsAtIndexPaths:withRowAnimation:insertSections:withRowAnimation:endUpdates都會導致這個警告。

PS:我嘗試重新加載表,但如果我向后導航,我會丟失 animation 以取消選擇行(清除行選擇)。

2019-09-27 09:40:42.849128+0200 xxx[63595:9762090] [TableView] 僅警告一次:UITableView 被告知布局其可見單元格和其他內容,而不是在視圖層次結構(表格視圖或其superviews 尚未添加到窗口中)。 這可能會在沒有准確信息的情況下強制表視圖內的視圖加載和執行布局(例如表視圖邊界、特征集合、布局邊距、安全區域插入等),從而導致錯誤,並且還會由於額外的布局傳遞而導致不必要的性能開銷. 在 UITableViewAlertForLayoutOutsideViewHierarchy 處創建一個符號斷點以在調試器中捕獲此問題並查看導致此問題發生的原因,因此您可以完全避免此操作,或者將其推遲到表視圖添加到 window 之前。 表視圖:; 層=; 內容偏移:{0,-64}; 內容大小:{375, 3432}; 調整內容插入:{64, 0, 0, 0}; 數據來源:>

// ------------  ------------  ------------  ------------  ------------  ------------
#pragma mark - FetchedResultsController delegate

- (void) controllerWillChangeContent:(NSFetchedResultsController *)controller {
//    if (self.tableView.window) {
        [self.tableView beginUpdates];
//    }
}
- (void) controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    if (type == NSFetchedResultsChangeInsert && newIndexPath != nil) {
        [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    }

    if (type == NSFetchedResultsChangeUpdate && indexPath != nil) {
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
//        id<CellLoadable> cell = [self.tableView cellForRowAtIndexPath:indexPath];
//        [cell loadData:anObject];
    }

    if (type == NSFetchedResultsChangeMove && indexPath != nil && newIndexPath != nil) {
        // if cell is visible, update it
        id<CellLoadable> cell = [self.tableView cellForRowAtIndexPath:indexPath];
        [cell loadData:anObject];
        [self.tableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
    }
}

- (void) controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    if (type == NSFetchedResultsChangeInsert) {
        [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
    }
    if (type == NSFetchedResultsChangeDelete) {
        [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
    }
}

- (void) controllerDidChangeContent:(NSFetchedResultsController *)controller {
//    if (self.tableView.window) {
        [self.tableView endUpdates];
//    }
}

PS: 任何一種 beginUpdates, reloadRowsAtIndexPaths:withRowAnimation: , insertSections:withRowAnimation: , endUpdates 都會引起這個警告。

我發現將表更新包裝在 dispatch_async 中觸發斷點的位置可以消除問題:

dispatch_async(dispatch_get_main_queue(), ^(void){
    [self.table reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
});

(可能必須在調用堆棧中斷時找到調用)

您可以嘗試下面的代碼,即檢查 window 並改為調用 reloadData。 僅供參考,這實際上並沒有重新加載所有單元格,它只是調用行數、節數等。然后接下來會出現新的單元格將被加載。 當視圖消失並在下次出現時重新加載表時,最好禁用獲取 controller。

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    if(!self.tableView.window){
        return;
    }
    [self.tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
    if(!self.tableView.window){
        return;
    }
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        default:
            return;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath {
    UITableView *tableView = self.tableView;
    if(!tableView.window){
        return;
    }
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeMove:
            [tableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] withEvent:anObject];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    if(!self.tableView.window){
        [self.tableView reloadData];
        return;
    }
    [self.tableView endUpdates];
}

請注意,您可能還想重新選擇以前選擇的單元格。 有幾種不同的方法可以做到這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM