无法在合理的时间内对该表达式进行类型检查 - ForEach SwiftUI
Posted
技术标签:
【中文标题】无法在合理的时间内对该表达式进行类型检查 - ForEach SwiftUI【英文标题】:Unable to type-check this expression in reasonable time - ForEach SwiftUI 【发布时间】:2020-04-07 16:30:20 【问题描述】:我有一个结构如下的 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
而且我需要列出特定建筑物中特定楼层的每个机柜的所有人 - 我在这里尝试这样做:
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)
但是,当我将第三个 ForEach
添加到视图代码时,我收到此错误 Unable to type-check this expression in reasonable time
。我从前一个视图中得到buildingId
和floorId
。什么是更有效的方法,所以我可以过滤橱柜和人员并修复此错误?谢谢。
【问题讨论】:
你添加的指令越多,它消耗的时间就越多......只需在几个子视图上打破那个 VStack 怪物。 但是当我仍然需要过滤槽 building.id 和 floor.id 以在层次结构中找到更深的对象时,这怎么可能?柜子和人? 顺便说一句,我在一个视图中也有一个三重 ForEach,虽然它编译正常,但在各种可重现的情况下,视图没有正确更新。将最后一个 ForEach 分离到另一个 View 中完全解决了这个问题。 【参考方案1】:编译器无法在合理的时间内对该表达式进行类型检查;尝试将表达式分解为不同的子表达式
SwiftUI 编译器告诉我们将表达式分解为子表达式。 换句话说,我们需要把这个视图分解成更小的子视图。
当SwiftUI
的编译器识别出可能导致性能问题的代码时,会弹出此类错误。
在您的情况下,您有一个循环中的循环,这可能是......不好!
话虽如此,SwiftUI 编译器仍在优化以处理像您这样的情况。
现在查看您的实现,从技术上讲它应该可以工作,但必须进行优化。
假设建筑物/楼层/机柜 ID 是唯一的,您的 ForEach
和 if
对建筑物和楼层的 ID 检查只会执行一次。
此外,您似乎只想展示橱柜,为什么不直接这样做呢?
解决办法:
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)
-
我们通过使用
buildingId
和floorId
使计算属性cabinets
通过ucmData
降低了复杂性
我们检查是否有橱柜可供展示。如果没有可用的橱柜,我们只会显示一条消息
CabinetView
被分离出来
【讨论】:
这是一个很好的解决方案,我不知道我可以像这样跳过检查建筑物和地板,谢谢! @redearz 很高兴能提供帮助 :) 好吧......自上而下的方法通常会受到清晰的影响,因为我们必须考虑多个事情。自下而上的方法使您可以专注于手头的任务。假设你有你需要的东西,处理它,然后弄清楚如何提供这个对象。【参考方案2】:我修复了这个问题,创建了 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)
【讨论】:
以上是关于无法在合理的时间内对该表达式进行类型检查 - ForEach SwiftUI的主要内容,如果未能解决你的问题,请参考以下文章
编译器无法在 SwiftUI 中的合理时间内对该表达式进行类型检查?
Xcode 编译器错误:编译器无法在合理的时间内对该表达式进行类型检查(Xcode 12.0 SwiftUI)