Crash with List using Observable Object

Hello,


I'm using swiftUI to render my interface, the goal is to made a simple tableView. I'm using List, passing a param that is an array from an observableObject. The array isn't empty and each element is one identifiable that has an UUID. But, my application crashes when I try to show the list on the screen. The error:



[TableView] Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window). This may cause bugs by forcing views inside the table view to load and perform layout without accurate information (e.g. table view bounds, trait collection, layout margins, safe area insets, etc), and will also cause unnecessary performance overhead due to extra layout passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch this in the debugger and see what caused this to occur, so you can avoid this action altogether if possible, or defer it until the table view has been added to a window. Table view: <_TtC7SwiftUIP33_BFB370BA5F1BADDC9D83021565761A4925UpdateCoalescingTableView: 0x14409f000; baseClass = UITableView; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x283e14f60>; layer = <CALayer: 0x2830b3fe0>; contentOffset: {0, 0}; contentSize: {0, 88}; adjustedContentInset: {0, 0, 0, 0}; dataSource: <_TtGC7SwiftUIP10$1f968ea4819ListCoreCoordinatorGVS_20SystemListDataSourceOs5Never_GOS_19SelectionManagerBoxS2___: 0x145160510>>


*** Assertion failure in -[_TtC7SwiftUIP33_BFB370BA5F1BADDC9D83021565761A4925UpdateCoalescingTableView _Bug_Detected_In_Client_Of_UITableView_Invalid_Number_Of_Sections:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore/UIKit-3899.22.15/UITableView.m:2396


The crash error message:


** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (1) must be equal to the number of sections contained in the table view before the update (1), plus or minus the number of sections inserted or deleted (1 inserted, 0 deleted).'

***



The code:

struct MyView: View {
    
    @ObservedObject var filesArray = MyFiles()
    
    var body: some View {
        VStack {
            MyFilesControllerWrapper(filesArray: filesArray)
            List(filesArray.files) { (file: MyFile) in
                NavigationLink(destination: MyDetailView(file: file) , label: { Text(file.filename ?? "") })
            }
        }
    }
}


The array class:

class MyFiles: NSObject, ObservableObject {
    @Published var files: [MyFile] = []
}


The item code:

class MyFile: NSObject, Identifiable, ObservableObject {
    var id = UUID()
    @Published var fileURL: URL
    var filename: String?

    ...

}


Accepted Reply

Hi,


I'm answering a little bit late but at least people with the same problem will have an answer.

I had the same problem today. This is generated by the fact that you are not giving your list a default content when tour files array is empty.
Try doing this:


List {
    if filesArray.files.isEmpty {
        emptySection
    } else {
        filesSection
    }
}


Then, outside of your body:


var emptySection: some View {
    Section {
        Text("No files found")
    }
}
  
var filesSection: some View {
    Section {
        ForEach(filesArray.files) { file in
            NavigationLink(destination: MyDetailView(file: file) , label: { Text(file.filename ?? "") })
        }
    }
}


You don't have to use the Section if you don't want to. Just remove it and leave the content.


Hope this helps!

  • That saved my life as well. Thanks for your solution.

Add a Comment

Replies

Hello, I have same problem.


Do you have solutions ?

Hi,


I'm answering a little bit late but at least people with the same problem will have an answer.

I had the same problem today. This is generated by the fact that you are not giving your list a default content when tour files array is empty.
Try doing this:


List {
    if filesArray.files.isEmpty {
        emptySection
    } else {
        filesSection
    }
}


Then, outside of your body:


var emptySection: some View {
    Section {
        Text("No files found")
    }
}
  
var filesSection: some View {
    Section {
        ForEach(filesArray.files) { file in
            NavigationLink(destination: MyDetailView(file: file) , label: { Text(file.filename ?? "") })
        }
    }
}


You don't have to use the Section if you don't want to. Just remove it and leave the content.


Hope this helps!

  • That saved my life as well. Thanks for your solution.

Add a Comment

I ended up using ForEach to fix that problem, with the List I had some limitations that was no longer a problem with ForEach.

The solution of @RolandAD saved my life. I was having this problem on iOS 13 but not in 14. I placed the empty section when my array is empty and solved the app crash.