最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

swift - Discrepancy between Preview and Running App - Stack Overflow

programmeradmin5浏览0评论

I am working on an app running on a Mac using XCode 16.2..

One view is displaying a table with some person data. The person might have several addresses. Because SwiftUI can only display 10 columns as a maximum, (several) address data is displayed in one table column and row. The table has a context menu, which will allow editing of the person data. On this editing page, the address list should be rendered as a table. In preview mode everything renders as expected, but when running the app, the edit page does not display the table with the address data.

ContentView is displaying the Person Table. If one Person is selected, the Edit-Context-Menu is enabled. This should display the PersonTableEditor. Unfortunately this view is not complete. What am I doing wrong?

struct ContentView: View {
  @State private var showingEditPage = false
  @State private var selected: Person.ID?
  @State var persons: [Person]
  @State var sortOrder = [KeyPathComparator(\Person.id)]

  var body: some View {
    VStack {
      Table(persons, selection: $selected, sortOrder: $sortOrder) {
        TableColumn("Name", value: \.name).width(100.0)
        TableColumn("Fistname", value: \.firstName ).width(100.0)
        TableColumn("Birthday", value: \.birthDate) { pers in
          Text(formatter.string(from: pers.birthDate))
        }.width(100.0)
        TableColumn("Addresses", value: \.addresses, comparator: KeyPathComparator(\[Address].description)) { pers in
          ForEach(pers.addresses) { adr in
            HStack {
              Text(adr.street)
              Text(adr.zip)
              Text(adr.city)
            }}
        }
      }
      .contextMenu(forSelectionType: Person.ID.self) { _ in
        Button("Edit ...") { showingEditPage = true}.disabled(selected == nil)
      }
      .sheet(isPresented: $showingEditPage) {
        PersonTableEditor(person: selectedPerson()!).id(UUID())
      }
    }
    .padding()
  }
  private func selectedPerson() -> Person? {
    guard let person = persons.first(where: {return $0.id == selected}) else { return nil
    }
    return person
  }
  private let formatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .medium
    return formatter
  }()
}

struct PersonTableEditor: View {

  @State var showingEditPage = false
  @State private var selected: Address.ID?
  @State var person: Person
  @State var sortOrder = [KeyPathComparator(\Address.id)]
  @State var perferred = false

  var body: some View {
    VStack {
      TextField("Name", text: $person.name)
      TextField("First", text: $person.firstName)
      DatePicker("Birthday", selection: $person.birthDate, displayedComponents: [.date])
      Table(person.addresses, selection: $selected, sortOrder: $sortOrder) {
        TableColumn("Preferred", value: \Address.preferred, comparator: BoolComparator()) { address in
          Text(address.preferred ? "Yes" : "No")
        }
        TableColumn("Street", value: \.street)
        TableColumn("Zip", value: \.zip)
        TableColumn("City", value: \.city)
      }.id(UUID())
        .contextMenu(forSelectionType: Person.ID.self) { _ in
          Button("Edit ...") { showingEditPage = true}.disabled(selected == nil)
        }
        .sheet(isPresented: $showingEditPage) {
          AddressTableEditor(address: selectedAddress()!)
        }
    }
    .padding()

  }
  private func selectedAddress() -> Address? {
    guard let adrs = person.addresses.first(where: {return $0.id == selected}) else { return nil
    }
    return adrs
  }
}

let persons = [
  Person(name: "Meier", firstName: "Hans", birthDate: Date(), addresses: [
    Address(street: "Mauernstr. 1", zip: "10000", city: "Berlin", preferred: false),
    Address(street: "Hafenstr. 2", zip: "20000", city: "Hamburg", preferred: true)
  ])
]

I have tried several setups for the PersonTableEditor without any success. Is the an other way to provide an editing architecture?

I am working on an app running on a Mac using XCode 16.2..

One view is displaying a table with some person data. The person might have several addresses. Because SwiftUI can only display 10 columns as a maximum, (several) address data is displayed in one table column and row. The table has a context menu, which will allow editing of the person data. On this editing page, the address list should be rendered as a table. In preview mode everything renders as expected, but when running the app, the edit page does not display the table with the address data.

ContentView is displaying the Person Table. If one Person is selected, the Edit-Context-Menu is enabled. This should display the PersonTableEditor. Unfortunately this view is not complete. What am I doing wrong?

struct ContentView: View {
  @State private var showingEditPage = false
  @State private var selected: Person.ID?
  @State var persons: [Person]
  @State var sortOrder = [KeyPathComparator(\Person.id)]

  var body: some View {
    VStack {
      Table(persons, selection: $selected, sortOrder: $sortOrder) {
        TableColumn("Name", value: \.name).width(100.0)
        TableColumn("Fistname", value: \.firstName ).width(100.0)
        TableColumn("Birthday", value: \.birthDate) { pers in
          Text(formatter.string(from: pers.birthDate))
        }.width(100.0)
        TableColumn("Addresses", value: \.addresses, comparator: KeyPathComparator(\[Address].description)) { pers in
          ForEach(pers.addresses) { adr in
            HStack {
              Text(adr.street)
              Text(adr.zip)
              Text(adr.city)
            }}
        }
      }
      .contextMenu(forSelectionType: Person.ID.self) { _ in
        Button("Edit ...") { showingEditPage = true}.disabled(selected == nil)
      }
      .sheet(isPresented: $showingEditPage) {
        PersonTableEditor(person: selectedPerson()!).id(UUID())
      }
    }
    .padding()
  }
  private func selectedPerson() -> Person? {
    guard let person = persons.first(where: {return $0.id == selected}) else { return nil
    }
    return person
  }
  private let formatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .medium
    return formatter
  }()
}

struct PersonTableEditor: View {

  @State var showingEditPage = false
  @State private var selected: Address.ID?
  @State var person: Person
  @State var sortOrder = [KeyPathComparator(\Address.id)]
  @State var perferred = false

  var body: some View {
    VStack {
      TextField("Name", text: $person.name)
      TextField("First", text: $person.firstName)
      DatePicker("Birthday", selection: $person.birthDate, displayedComponents: [.date])
      Table(person.addresses, selection: $selected, sortOrder: $sortOrder) {
        TableColumn("Preferred", value: \Address.preferred, comparator: BoolComparator()) { address in
          Text(address.preferred ? "Yes" : "No")
        }
        TableColumn("Street", value: \.street)
        TableColumn("Zip", value: \.zip)
        TableColumn("City", value: \.city)
      }.id(UUID())
        .contextMenu(forSelectionType: Person.ID.self) { _ in
          Button("Edit ...") { showingEditPage = true}.disabled(selected == nil)
        }
        .sheet(isPresented: $showingEditPage) {
          AddressTableEditor(address: selectedAddress()!)
        }
    }
    .padding()

  }
  private func selectedAddress() -> Address? {
    guard let adrs = person.addresses.first(where: {return $0.id == selected}) else { return nil
    }
    return adrs
  }
}

let persons = [
  Person(name: "Meier", firstName: "Hans", birthDate: Date(), addresses: [
    Address(street: "Mauernstr. 1", zip: "10000", city: "Berlin", preferred: false),
    Address(street: "Hafenstr. 2", zip: "20000", city: "Hamburg", preferred: true)
  ])
]

I have tried several setups for the PersonTableEditor without any success. Is the an other way to provide an editing architecture?

Share Improve this question edited yesterday koen 5,7297 gold badges58 silver badges101 bronze badges asked 2 days ago hjbflyerhjbflyer 7911 bronze badges 6
  • Please show a minimal reproducible example - something I can copy and paste into a new Xcode project and reproduce the issue. – Sweeper Commented 2 days ago
  • Your question should be self-contained. Please make an effort to isolate the problem and post only the minimal code required to reproduce the problem. – Sweeper Commented 2 days ago
  • This is the minimal example code. It shows the working Previews and the bug when running the App. – hjbflyer Commented 2 days ago
  • In my example there is a Table with context menus. The context menu is opening an other View (.sheet). This view is not able to display an other Table. I think it is a BUG in the Table implementation. There is no log entry. In the view there is nothing (or just an EmptyView instead of the Table). In the preview, everything renders correctly. – hjbflyer Commented 7 hours ago
  • @Sweeper. I have prepared a smaller example to demonstrate the bug. – hjbflyer Commented 6 hours ago
 |  Show 1 more comment

1 Answer 1

Reset to default 0

Finally I have found a work around. Just append the .frame(height: 200.0) modifier to the VStack with a value large enough to display the table. If the value is too small, the table won't be rendered.

发布评论

评论列表(0)

  1. 暂无评论