简体   繁体   中英

SwiftUI The compiler is unable to type-check this expression in reasonable time

I could compile and run these code successfully before I updated Xcode to version 13.0. But this error shows up now.

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

I tried to break down my views and reproduce it like this. I found the problem is on line 21. The code:

import SwiftUI

struct EmojiView: View {
    
    var EmojiArr: [Int] = [0x1f601, 0x1f602, 0x1f603, 0x1f604, 0x1f605, 0x1f606, 0x1f607, 0x1f608, 0x1f609]
    
    func GetVstackNum(num: Int) -> Int {
        if num % 3 == 0 {
            return num / 3
        } else  {
            return num / 3 + 1
        }
    }
    
    var body: some View {
        HStack(spacing: 10) {
            let length = EmojiArr.count
            if length > 0 {
                ForEach(0 ... (GetVstackNum(num: length) - 1), id: \.self) { i in
                    VStack(alignment: .leading, spacing: 22) {
                        ForEach((3 * i) ... (3 * i + 2), id: \.self) { j in
                            if j < length {
                                Button(action: {
                                    // Some button action
                                }) {
                                    if (UnicodeScalar(EmojiArr[j])?.properties.isEmoji)! {
                                        Text(String(UnicodeScalar(EmojiArr[j])!)).font(.system(size:17))
                                    }
                                    else {
                                        Text("")
                                    }
                                }
                                .frame(width: 20, height: 10, alignment:.topLeading)
                                .buttonStyle(PlainButtonStyle())
                            }
                        }
                    }
                    .frame(height: 83, alignment:.topLeading)
                }
            }
        }
    }
}

How to fix this?

Your Code worked fine when I tested it using xcode 12.3 on macOS 11.2.3. You can try using return HStack and see if the problem still persists. The above answer has some good tips as well

import SwiftUI

struct EmojiView: View {
    
    var EmojiArr: [Int] = [0x1f601, 0x1f602, 0x1f603, 0x1f604, 0x1f605, 0x1f606, 0x1f607, 0x1f608, 0x1f609]
    
    func GetVstackNum(num: Int) -> Int {
        if num % 3 == 0 {
            return num / 3
        } else  {
            return num / 3 + 1
        }
    }
    
    var body: some View {
        return HStack(spacing: 10) {
            let length = EmojiArr.count
            if length > 0 {
                ForEach(0 ... (GetVstackNum(num: length) - 1), id: \.self) { i in
                    VStack(alignment: .leading, spacing: 22) {
                        ForEach((3 * i) ... (3 * i + 2), id: \.self) { j in
                            if j < length {
                                Button(action: {
                                    // Some button action
                                }) {
                                    if (UnicodeScalar(EmojiArr[j])?.properties.isEmoji)! {
                                        Text(String(UnicodeScalar(EmojiArr[j])!)).font(.system(size:17))
                                    }
                                    else {
                                        Text("")
                                    }
                                }
                                .frame(width: 20, height: 10, alignment:.topLeading)
                                .buttonStyle(PlainButtonStyle())
                            }
                        }
                    }
                    .frame(height: 83, alignment:.topLeading)
                }
            }
        }
    }
}

You should do what the error message tells you.

I think the struggle the compiler has, is that the if j < length {... } does not have an else case with a View. Try this as a test (but do what the error message tells you), works for me on macos 12, xcode 13-beta5 (not release):

var body: some View {
    HStack(spacing: 10) {
        let length = EmojiArr.count
        if length > 0 {
            ForEach(0 ... (GetVstackNum(num: length) - 1), id: \.self) { i in
                VStack(alignment: .leading, spacing: 22) {
                    ForEach((3 * i) ... (3 * i + 2), id: \.self) { j in
                        if j < length {
                            Button(action: { }) {
                                if let emo = UnicodeScalar(EmojiArr[j]), emo.properties.isEmoji {
                                    Text(String(emo)).font(.system(size:17))
                                } else {
                                    Text("")
                                }
                            }
                            .frame(width: 20, height: 10, alignment:.topLeading)
                            .buttonStyle(PlainButtonStyle())
                        } else {
                            Text("") // <-- here
                        }
                    }
                }
                .frame(height: 83, alignment:.topLeading)
            }
        }
    }
}

And don't use force unwrap in your code.

Generally, with SwiftUI it's better to try to minimize the number of conditionals that are directly within a View's body. (harder to grok, can cause extra runtime re-rendering, and as here, cause Xcode to run out of patience (possibly dependent on vintage of the build mac) trying to figure out what's going on ). The Xcode problem occurs particularly if the branches of the conditionals result in the return of a different View type.

The solution, as hinted by Xcode, is to abstract out parts so that Xcode can check each bit more easily and match return View types.

With Xcode 13 beta 4 and iOS15 the following works for me and doesn't attempt to melt my intel mac:

import PlaygroundSupport
import SwiftUI

import SwiftUI

struct EmojiView: View {
    let emojiArr: [Int] = [0x1F601, 0x1F602, 0x1F603, 0x1F604, 0x1F605, 0x1F606, 0x1F607, 0x1F608, 0x1F609]
    var length: Int { emojiArr.count }

    func getVstackNum(num: Int) -> Int {
        if num % 3 == 0 {
            return num / 3
        } else {
            return num / 3 + 1
        }
    }

    func customButton(_ j: Int) -> some View {
        return Button(action: {
            // Some button action
        }) {
            if (UnicodeScalar(emojiArr[j])?.properties.isEmoji)! {
                Text(String(UnicodeScalar(emojiArr[j])!)).font(.system(size: 17))

            } else {
                Text("")
            }
        }
    }

    func customRows(_ i: Int) -> some View {
        return VStack(alignment: .leading, spacing: 22) {
            ForEach((3 * i) ... (3 * i + 2), id: \.self) { j in
                if j < length {
                    customButton(j)
                        .frame(width: 20, height: 10, alignment: .topLeading)
                        .buttonStyle(PlainButtonStyle())
                }
            }
        }
    }

    var body: some View {
        HStack(spacing: 10) {
            if length > 0 {
                ForEach(0 ... (getVstackNum(num: length) - 1), id: \.self) { i in
                    customRows(i)
                        .frame(height: 83, alignment: .topLeading)
                }
            }
        }
        .padding()
    }
}

let view = EmojiView()
PlaygroundPage.current.setLiveView(view)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM