Xcode报错:The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
Xcode报错:The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

Xcode报错:The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

问题描述

将练习的代码改为SwiftData后,单个预览信息的视图显示报错。

报错代码为

Compiling failed: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

报错视图的作用是预览SwiftData选择的单个对象的信息。

起初思考的是,没有引入SwiftData导致的,引入SwiftData后仍然报错。考虑到这个视图只是显示SwiftData单个对象的信息,而且这个对象是从外部传递进来,跟普通对象没有区别,因此SwiftData不应该是报错的原因。

然后通过排查法,将主要的几个复杂代码一一注释掉:

1、注释掉GeometryReader

VStack(alignment: .leading, spacing: 0) {
    Image(decorative: resort.id)
        .resizable()
        .scaledToFit()
        // .overlay {
        //  GeometryReader { geometry in
        //      let positionX = geometry.size.width
        //      let positionY = geometry.size.height
        //      ...
        //  }
        // }
}

2、注释掉Group中的ForEach

Group {
    Text(resort.description)
        .padding(.vertical)
    Text("Facilities")
        .font(.headline)
    // HStack {
    //  ForEach(facilityTypes) { facility in
    //      Button {
    //          selectedFacility = facility
    //          showingFacility = true
    //      } label: {
    //          facility.icon
    //              .font(.title)
    //      }
    //  }
    // }
    // .padding(.vertical)
}
.padding(.horizontal)

即使注释掉比较复杂的代码,仍然存在报错。

然后我把navigationTitle、navigationBarTitleDisplayMode等外层修饰符也注释掉。

//        .navigationTitle("\(resort.name), \(resort.country)")
//        .navigationBarTitleDisplayMode(.inline)
//        .alert(selectedFacility?.name ?? "More information",
//               isPresented: $showingFacility,
//               presenting: selectedFacility) { _ in
//        } message: { facility in
//            Text(facility.description)
//        }

当注释掉外面的修饰符后,报错的信息变成:

Compiling failed: value of type 'Resort' has no member 'description'

问题原因

这时我就知道,报错的原因为:类型“Resort”的值没有成员“description”。

在SwiftData改动的过程中,因为无法使用description关键字作为Resort的参数,因此将description字段名称改为resortdescription,然后通过CodingKeys进行映射。

解决方案

因此,将视图中涉及description属性的字段修改为resortdescription。

Text(resort.description)

修改为:

Text(resort.resortdescription)

问题得到解决。

总结

Xcode第一时间没有报出这个问题,可能就是嵌套的代码太多,Xcode无法将这个问题抛出。因此,当遇到同类问题时,通过排查法把嵌套或较为复杂的代码注释掉,特别是外层的navigation之类的修饰符也注释掉,然后检查Xcode预览输出的实际报错,进而整个相关的报错问题。

相关文章

Xcode报错:A stored property cannot be named ‘description’: https://fangjunyu.com/2024/12/24/xcode%e6%8a%a5%e9%94%99%ef%bc%9aa-stored-property-cannot-be-named-description/

扩展知识

Text拼接报错

还有一个报错场景,那就是当代码存在多层嵌套时,Text拼接就可能导致预览报错。

例如下面这段代码,存在多层嵌套:

Group {
    // 其他代码
    Group {
        // 其他代码
        if  piggyBank[0].amount == piggyBank[0].targetAmount {
            // 省略代码
        } else {
            // 报错代码
            if SwitchTopStyle {
                Text("\(piggyBank[0].name)" + "Deposited")
                    .lineLimit(2)
                    .minimumScaleFactor(0.5)
            } else {
                Text("Distance" + "\(piggyBank[0].name)" + "Need")
                    .lineLimit(2)
                    .minimumScaleFactor(0.5)
            }
        }
    }
}

在我新增if-else代码嵌套后,Xcode预览报错并输出:

Compiling failed: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

在我隐藏代码进行排除问题,发现问题在于Text代码块:

Text("\(piggyBank[0].name)" + "Deposited")

这种拼接的Text如果在正常的视图下,预览是正常的,但是如果存在多层条件判断语句,例如if-else代码中,就可能发现报错。

解决方案就是将这种拼接的Text代码改为普通的Text视图显示:

if SwitchTopStyle {
    HStack {
        Text(piggyBank[0].name)
        Text("Deposited")
    }
    .lineLimit(2)
    .minimumScaleFactor(0.5)
} else {
    HStack {
        Text("Distance")
        Text(piggyBank[0].name)
        Text("Need")
    }
    .lineLimit(2)
    .minimumScaleFactor(0.5)
}

Binding报错

当Swift无法在编译时快速推断TextField的Binding表达式类型,尤其是涉及:

1)条件逻辑。

2)泛型(Binding)。

3)多层访问数组、optional、结构体等。

也可能导致这个报错。

例如下面这个代码中,在一个视图文件中,第二个TextField没有问题,第一个TextField就会报错。

TextField("0.0", text: Binding(
    get: {
        inputs.first(where: { $0.id == currency.symbol })?.value ?? ""
    },
    set: { newValue in
        if let index = inputs.firstIndex(where: { $0.id == currency.symbol }) {
            inputs[index].value = newValue
        } else {
            inputs.append(CurrencyInput(id: currency.symbol, value: newValue))
        }
    }
))

依次排查发现,当隐藏append方法后,不再报编译错误。

解决方案为:将 Binding 单独写成变量,交由 Swift 编译器逐步推断,可以显著降低复杂度。

let binding = Binding(
    get: {
        inputs.first(where: { $0.id == currency.symbol })?.value ?? ""
    },
    set: { newValue in
        if let index = inputs.firstIndex(where: { $0.id == currency.symbol }) {
            inputs[index].value = newValue
        } else {
            inputs.append(CurrencyInput(id: currency.symbol ?? "", value: newValue))
        }
    }
)

TextField("0.0", text: binding)

经常查询了解到,第二个TextField能编译成功,可能是因为那个视图的结构更简单,或者currency类型是明确的String,而不是optional,所以Swift编译器推断起来更轻松。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注