Невозможно проверить это выражение в разумные сроки - ForEach SwiftUI - PullRequest
1 голос
/ 07 апреля 2020

У меня есть файл JSON, структурированный так:

// MARK: - UcmData
struct UcmData: Codable, Identifiable {
    let id: Int
    let building: [Building]
}

// MARK: - Building
struct Building: Codable, Identifiable {
    let id: Int
    let title, subtitle, info, image: String
    let floor: [Floor]
}

// MARK: - Floor
struct Floor: Codable, Identifiable {
    let id, number: Int
    let title, subtitle, image: String
    let cabinet: [Cabinet]?
}

// MARK: - Cabinet
struct Cabinet: Codable, Identifiable {
    let id: Int
    let number: String
    let person: [Person]
}

// MARK: - Person
struct Person: Codable, Identifiable {
    let id: Int
    let name: String
}

И мне нужно перечислить всех людей для каждой кабины inet на указанном c этаже в указанном c здании - Я пытаюсь сделать это здесь:

import SwiftUI

struct FloorDetailedView: View {
    let ucmData = Bundle.main.decode(UcmData.self, from: "ucm_data.json")
    let buildingId: Int?
    let floorId: Int?
    let floorTitle: String?
    let buildingTitle: String?

    init(buildingId: Int? = nil, floorId: Int? = nil, floorTitle: String? = "nil", buildingTitle: String? = "nil") {
        self.buildingId = buildingId
        self.floorId = floorId
        self.floorTitle = floorTitle
        self.buildingTitle = buildingTitle

    }

    var body: some View {
        ScrollView {
            VStack {
                ForEach(ucmData.building) { building in
                    if (building.id == self.buildingId) {
                        ForEach(building.floor) { floor in
                            if (floor.id == self.floorId) {
                                ForEach(floor.cabinet) { cabinet in
                                    Image(systemName: "house")
                                        .cornerRadius(40)
                                    VStack(alignment: .leading) {
                                        Text(cabinet.name)
                                        ForEach(cabinet.person) { person in
                                            Text(person.name)
                                                .font(.subheadline)
                                                .color(.gray)
                                        }
                                    }
                                }
                            }
                        }
                    }
                }   
            }
            .padding(.horizontal)
            .padding(.bottom)
        }
        .navigationBarTitle(Text(self.buildingTitle! + " - " + self.floorTitle!), displayMode: .inline)
    }
}

Однако, я получаю эту ошибку Unable to type-check this expression in reasonable time, когда я добавляю 3-й ForEach к коду вида. Я получаю buildingId и floorId из предыдущего представления. Что является более эффективным способом, чтобы я мог отфильтровать кабинеты и людей и исправить эту ошибку? Спасибо.

Ответы [ 2 ]

1 голос
/ 07 апреля 2020

Компилятор не может проверить это выражение в разумные сроки; попробуйте разбить выражение на отдельные подвыражения

Компилятор SwiftUI говорит нам разбить выражение на подвыражения.
Другими словами, нам нужно разбить это представление на более мелкие views.

Такая ошибка появляется, когда компилятор SwiftUI идентифицирует код, который может привести к проблемам с производительностью.
В вашем случае у вас есть oop в oop в oop и это может быть ... плохо!

При этом компилятор SwiftUI все еще оптимизируется для обработки таких случаев, как ваш.


Теперь, глядя на вашу реализацию, технически она должна работать, но должна быть оптимизирована.
Если предположить, что идентификаторы здания / этажа / кабины inet уникальны, ваши проверки идентификаторов ForEach и if для здания и этажа будут выполняться только один раз.
Кроме того, кажется, что вы хотите показать только шкафы так почему бы не go прямо для этого?

Решение:

struct FloorDetailedView: View {
  let ucmData: UcmData
  let buildingId: Int?
  let floorId: Int?

  var cabinets: [Cabinet]? { //1
    return ucmData
      .building
      .first { $0.id == self.buildingId }?
      .floor
      .first { $0.id == self.floorId }?
      .cabinet
  }

  var body: some View {
    Group {
      if cabinets != nil { //2
        CabinetView(cabinets: cabinets!) //3
      } else {
        Text("No Cabinets")
      }
    }
  }
}

struct CabinetView: View {
  let cabinets: [Cabinet]

  var body: some View {
    List(cabinets) { (cabinet) in
      VStack(alignment: .leading) {
        Image(systemName: "house")

        Text(cabinet.number)

        ForEach(cabinet.person) { (person) in
          Text(person.name)
        }
      }
    }
  }
}
  1. Мы уменьшили сложность, имея вычисляемое свойство cabinets, которое проходит через ucmData, используя buildingId и floorId
  2. Мы проверяем, доступны ли шкафы для показа. Если нет доступных шкафов, мы просто показываем сообщение
  3. CabinetView выделено
0 голосов
/ 07 апреля 2020

Я исправил это, создав 2 отдельных вида:

import SwiftUI

struct CabinetView: View {
    let floor: Floor?
    let floorId: Int?

    init(floor: Floor? = nil, floorId: Int? = nil) {
        self.floor = floor
        self.floorId = floorId
    }

    var body: some View {
        ForEach(floor!.cabinet!) { cabinet in
            Group {
                HStack {
                     Image("avatar")
                        .resizable()
                        .frame(width: 40, height: 40)
                        .border(Color.gray.opacity(0.5), width: 0.5)
                        .cornerRadius(40/2)
                    VStack(alignment: .leading, spacing: 3) {
                        Text(cabinet.number)
                        ForEach(cabinet.person) { person in
                            Text(person.name)
                                .font(.subheadline)
                        }
                    }
                }
            }
        }
    }
}

и этот:

import SwiftUI

struct FloorDetailedView: View {
    let ucmData = Bundle.main.decode(UcmData.self, from: "ucm_data.json")
    let buildingId: Int?
    let floorId: Int?
    let floorTitle: String?
    let buildingTitle: String?

    init(buildingId: Int? = nil, floorId: Int? = nil, floorTitle: String? = "nil", buildingTitle: String? = "nil") {
        self.buildingId = buildingId
        self.floorId = floorId
        self.floorTitle = floorTitle
        self.buildingTitle = buildingTitle

    }

    var body: some View {
            List {
                ForEach(ucmData.building) { building in
                    if (building.id == self.buildingId) {
                        ForEach(building.floor) { floor in
                            if (floor.id == self.floorId) {
                                CabinetView(floor: floor, floorId: self.floorId)
                            }
                        }
                    }
                }
            }
            .padding(.horizontal)
            .padding(.bottom)
            .navigationBarTitle(Text(self.buildingTitle! + " - " + self.floorTitle!), displayMode: .inline)
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...