SwiftUI Runtime Error from if condition { Text() } in watchOS

As far as I read about conditional Views this code should work. But it doesn't.

Code Block
struct Consts {
static let myCondition = false /* no difference if true or false */
}
struct ContentView: View {
@State var toggle: Bool = false
var body: some View {
List() {
Text("Short Text is in first line")
Text("Second Line Text is a little longer but not much")
if Consts.myCondition {
Text("This is a conditional text. As in: when the user hasn't purchased the option he / she don't need a hint how to use this feature.")
/* } else {
Text("else doesn't help either.") */
}
Toggle("I also have a toggle but it has nothing to do with this.", isOn: $toggle)
Text("Here we have a longer Text. Dont know what to type any more.")
Text("More text which is longer than a few lines.")
Text("Not so long Text")
}
.navigationTitle("Hints & Settings")
}
}


It compiles without warnings or errors. It loads up and displays fine, on simulator and on device. But every time I scroll the List upwards from the end, as soon as this if condition { Text() } should become visible the app crashes with

Code Block
Fatal error: file SwiftUI, line 0
2021-03-07 06:36:26.548126+0100 WTFif WatchKit Extension[23163:641812] Fatal error: file SwiftUI, line 0


This is not limited to watchOS. It reproduces the same way in iOS, just the Texts have to be longer so that the if condition { Text() } becomes invisible when scrolling.

I have worked around the error with an array, conditional ranges and two ForEach() blocks.

Code Block
struct ContentView: View {
let myHints = ["Short Text is in first line",
"Second Line Text is a little longer but not much",
"This is a conditional text. As in: when the user hasn't purchased the option he / she don't need to hint how to use this feature.",
"Here we have a longer Text. Dont know what to type any more.",
"More text which is longer than a few lines.",
"Not so long Text"]
var myUpperRange: ClosedRange<Int> {
if Consts.myCondition {
return 0...1
} else {
return 0...2
}
}
var myLowerRange: ClosedRange<Int> {
return 3...5
}
@State var toggle: Bool = false
var body: some View {
List() {
ForEach (myUpperRange, id: \.self) { i in
Text(myHints[i])
}
Toggle("I also have a toggle but it has nothing to do with this.", isOn: $toggle)
ForEach (myLowerRange, id: \.self) { i in
Text(myHints[i])
}
}
.navigationTitle("Hints & Settings")
}
}


My question basically is: am I not getting it or did I find a bug in Xcode / SwiftUI? Should my code above work? What could I have done different to make it work with the simple list of Texts?

Background: I also have a TabView with an if condition { MyTab() } which works without crashing. Do I have to worry that this might crash in the same way? Should I work around this as well before shipping?

PS: I am using Xcode 12.4 (12D4e)

Answered by ForumsContributor in
Hi MDeuschl,

Logically, your program should run just fine. I suspect that you are right, that it's a bug with SwiftUI itself. I have the same Fatal error: file SwiftUI, line 0 error for my code. In my case, I conditionally render a view based on whether the variable holding the view is nil. A different situation than yours, but the same error, and for no clear reason. I wish I had more information on how to avoid it. All I know for now is that you can submit a Feedback Assistant with a sample Xcode project that demonstrates the crash. I'll probably do this when I have more time.

Here's my code. I display my view in another view that is displayed in a modal sheet. The whole modal setup works fine in a SwiftUI Preview, but always crashes on simulator and device.

Code Block swift
import SwiftUI
/// A view with an action button that should be presented modally.
struct ActionModalView: View {
  let iconImage: Image?
  let title: String
  let message: String
  let buttonText: String
  let buttonAction: () -> Void
  var body: some View {
    VStack(spacing: Theme.Spacing.extraExtraLarge) {
      Spacer(minLength: Theme.Spacing.extraExtraLarge)
// This causes a crash
      if let iconImage = iconImage {
        iconImage
          .resizable()
          .renderingMode(.template)
          .foregroundColor(.primaryBase)
          .aspectRatio(contentMode: .fit)
          .frame(width: 80)
      }
      Text(title)
        .font(Theme.Text.largeTitle)
      FadingScrollView {
        Text(message)
          .font(Theme.Text.title3)
      }
      actionButton
    }
    .padding(.horizontal, Theme.Spacing.extraExtraLarge)
    .background(Color.adaptiveSecondaryBackground)
  }
  var actionButton: some View {
    Button(action: buttonAction) {
      HStack {
        Spacer()
        Text(buttonText)
          .font(Theme.Text.title3)
          .foregroundColor(.textXlight)
        Spacer()
      }
      .padding()
      .background(Color.primaryBase)
      .cornerRadius(10)
    }
  }
}
struct ActionModalView_Previews: PreviewProvider {
  static var previews: some View {
    LightAndDarkPreviewGroup(layoutMode: .largeAndSmallDevices) {
      Group {
        Text("Press the play button to view the ActionModalView with a large amount of text.")
          .sheet(isPresented: .constant(true)) {
            ActionModalView(
              iconImage: Image(uiImage: Asset.runningshoe.image),
              title: "This is the title",
              message: PreviewFixtures.Text.threeParagraphs,
              buttonText: "Action Button",
              buttonAction: {}
            )
          }
        Text("Press the play button to view the ActionModalView with a small amount of text.")
          .sheet(isPresented: .constant(true)) {
            ActionModalView(
              iconImage: Image(uiImage: Asset.runningshoe.image),
              title: "This is the title",
              message: PreviewFixtures.Text.oneParagraph,
              buttonText: "Action Button",
              buttonAction: {}
            )
          }
      }
    }
  }
}

Hi again MDeuschl,

I was able to fix the crash in my app. It turns out that in my code that uses my ActionModalView in my previous post, SwiftUI accesses a computed variable, which is generated using the following code:

Code Block
extension String {
  var htmlToString: String {
    return htmlToAttributedString.string
      .trimmingCharacters(in: .whitespacesAndNewlines)
  }
  private var htmlToAttributedString: NSAttributedString {
    guard let data = data(using: .utf8) else { return NSAttributedString() }
    do {
      return try NSAttributedString(
        data: data,
        options: [
          .documentType: NSAttributedString.DocumentType.html,
          .characterEncoding: String.Encoding.utf8.rawValue
        ],
        documentAttributes: nil)
    } catch {
      return NSAttributedString()
    }
  }
}


It turns out that there's some sort of bug where creating an NSAttributedString with NSAttributedString.DocumentType.html cannot be done on a SwiftUI thread. On iOS 13, it results in a crash, while on iOS 14 it results in a slowdown, and a crash in another part of SwiftUI code. Removing this fixed my issue with my usage of if let iconImage = iconImage in SwiftUI. So it turns out that my usage of if let iconImage = iconImage wasn't really a problem in the first place, and that SwiftUI was doing a really poor job of helping me pinpoint the issue with NSAttributedString. I suspect something similar might be happening in your case. Hopefully SwiftUI improves this year.
It seems we have encountered different problems with the same error message?

I have not posted my full code, but the main difference between yours and mine is that Consts.myCondition is never changed after compiling. I originally wanted to do a #ifdef but I found that's not supported by swift. Just now I read about Build Configurations - will have to look into this.

At least it seems more and more clear that it's not my understanding of SwiftUI that's at fault here... like you said if I can find the time I'll post a bug report.
Accepted Answer

Apparently this has been fixed by iOS 15 Beta 4: on my test device I had the error prior to the Beta 4 update, using a test app compiled with Xcode 13 Beta 3. After the update to iOS 15 Beta 4 the error is gone. (Xcode Beta 4 is still downloading currently.)

So I think it’s reasonable to say that the update to iOS 15 Beta 4 did fix the error.

Apple Feedback ID FB9063694

If any1 would like to confirm…?

SwiftUI Runtime Error from if condition { Text() } in watchOS
 
 
Q