skip to Main Content

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?

3

Answers


  1. 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.

    Login or Signup to reply.
  2. 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)
                    }
                }
            }
        }
    }
    
    Login or Signup to reply.
  3. 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)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search