I forgot to mention what my model looked like. A simplified version of it looks like this:
@Model class FMList {
var listID: UUID
var name: String
var isFavorite: Bool
// init func omitted for brevity
}
Post
Replies
Boosts
Views
Activity
it looks like I had left some test code in my List example I initially provided. The below code is what I'm actually using (no online filtering, I'm using the computed property) For the user todo lists section.
// MARK: -- User TodoLists
Section(header: Text("Lists").padding(.top, -24)) {
ForEach(userTodoLists) { list in
NavigationLink(value: list) {
Text(list.name)
}
}
}
}
I still haven't figured out why this is happening. I'm moving forward with manually updating the arrays but would still like to understand if the SwiftData changes to the array are supposed to be picked up by SwiftUI. If so, then I can file a bug but I'm not sure how to tell if this is expected behavior or not.
I had not tried that actually so I just did and received a ton of compiler errors. I uploaded a new GIST of the errors. Why do I not receive these during a normal Run while in the Debug config?
I have done some additional testing. Since all of the Archive compiler errors I'm getting now exist within the #Preview macros used in the Views I removed them all. Once I deleted all of the #Preview macros in the app I could delete the SampleData.swift and PreviewContainer.swift files that the compiler wasn't finding.
Now those files don't exist and I can continue to build and run the app normally. However Release build still fail with the same compiler error and the Archive command fails with the same Command SwiftCompile failed with a nonzero exit code build error. Looking at the log (here) it looks like the same result as my Release builds - no details.
I don't understand why Archive was failing to build with all the #Preview macros - I'll have to circle back around and look at that later. At the moment though, both Release builds and Archive is failing with the same nonzero exit code failure.
I have been able to fully reproduce this issue in a sample app. The following code will build, and run on both a simulator and a device. It will also work in XCode preview. When I attempt to archive it or run a Release config, it fails with the nonzero error.
import SwiftUI
class MyModel {
var name: String
var children: [MyModel] = []
init(name: String) { self.name = name }
}
struct MyModelPicker: View {
private var items: [MyModel] = []
init() {
let foo = MyModel(name: "Foo")
let bar = MyModel(name: "Bar")
let people = MyModel(name: "People")
let johnDoe = MyModel(name: "John Doe")
let maryJane = MyModel(name: "Mary Jane")
let childDoe = MyModel(name: "Child of Doe")
johnDoe.children.append(childDoe)
people.children.append(contentsOf: [ johnDoe, maryJane ])
foo.children.append(bar)
items = [ foo, people ]
}
var body: some View {
List {
ForEach(items, id: \.name) { item in
getRowForUserList(item)
}
}
}
@ViewBuilder func getRowForUserList(_ list: MyModel) -> some View {
if list.children.isEmpty {
Text(list.name)
} else {
getRowForParent(list)
}
}
@ViewBuilder func getRowForParent(_ list: MyModel) -> some View {
DisclosureGroup(isExpanded: .constant(true)) {
ForEach(list.children, id: \.name) { child in
getRowForUserList(child)
}
} label: {
Text(list.name)
}
}
}
struct ContentView: View {
var body: some View {
VStack {
MyModelPicker()
}
}
}
#Preview {
ContentView()
}
With this reproducible, I submitted bug report FB15926480 with this example project included. Within the getRowForParent function there is the following loop:
ForEach(list.children, id: \.name) { child in
getRowForUserList(child)
}
Commenting out the getRowForuserList function call will allow archiving to complete successfully. It seems to be an issue with recursion of the views.
After some additional debugging, I have found that replacing the usage of @ViewBuilder with dedicated structs allows for archive builds to be created. I can copy the implementation of each ViewBuilder as-is with no changes and past them into structs. Release configuration and Archiving compiles successfully.
The revised code is below - again with no implementation changes other than pulling the code out of ViewBuilder and into a struct.
import SwiftUI
@Observable class MyModel {
var name: String
var children: [MyModel] = []
init(name: String) { self.name = name }
}
struct MyModelPicker: View {
private var items: [MyModel] = []
init() {
let foo = MyModel(name: "Foo")
let bar = MyModel(name: "Bar")
let people = MyModel(name: "People")
let johnDoe = MyModel(name: "John Doe")
let maryJane = MyModel(name: "Mary Jane")
let childDoe = MyModel(name: "Child of Doe")
johnDoe.children.append(childDoe)
people.children.append(contentsOf: [ johnDoe, maryJane ])
foo.children.append(bar)
items = [ foo, people ]
}
var body: some View {
List {
ForEach(items, id: \.name) { item in
RowView(list: item)
}
}
}
}
struct RowView: View {
@Bindable var list: MyModel
var body: some View {
if list.children.isEmpty {
Text(list.name)
} else {
ParentRowView(list: list)
}
}
}
struct ParentRowView: View {
@Bindable var list: MyModel
var body: some View {
DisclosureGroup(isExpanded: .constant(true)) {
ForEach(list.children, id: \.name) { child in
RowView(list: child)
}
} label: {
Text(list.name)
}
}
}
struct ContentView: View {
var body: some View {
VStack {
MyModelPicker()
}
}
}
#Preview {
ContentView()
}
I have updated my bug report to indicate this. It seems this is an issue with @ViewBuilder being able to recursively construct views.